home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / file.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  97KB  |  3,020 lines

  1. /*
  2.  * This file contains the file i/o stuff.  These functions get stuff from
  3.  * from the outside world into a form for TDE.  The form TDE uses is a
  4.  * double linked list.  Each node in the list points to the prev and
  5.  * the next nodes, if they exist.  Also in each node is a pointer to a
  6.  * line of text, a line length variable, and a dirty node indicator.  In
  7.  * earlier versions of TDE, a '\n' was used to terminate a line of text.
  8.  * In this version, we must keep an accurate count of characters in
  9.  * each line of text, as no character is used to terminate the line.
  10.  *
  11.  * Each file must contain at least one node.  That node is called the
  12.  * EOF node.  The EOF node terminates the double linked list for each
  13.  * file.  The EOF node has a NULL pointer in the line field, a NULL
  14.  * pointer in the next field, and an EOF in the len field.  Here's
  15.  * a crude picture of the double linked list structure:
  16.  *
  17.  *              Regular node                             EOF node
  18.  *     ---------                                 ---------
  19.  *     | prev  | ---> pointer to prev node       | prev  | ---> unknown
  20.  *     | line  | ---> "Hello world"              | line  | ---> NULL
  21.  *     | len   | ---> 11                         | len   | ---> EOF
  22.  *     | dirty | ---> TRUE | FALSE               | dirty | ---> FALSE
  23.  *     | next  | ---> pointer to next node       | next  | ---> NULL
  24.  *     ---------                                 ---------
  25.  *
  26.  * Implicitly, I am assuming that EOF is defined as (-1) in stdio.h.
  27.  *
  28.  * The load_file function is probably more complicated than expected, but
  29.  * I was trying to read chunks of text that match the disk cluster size
  30.  * and/or some multiple of the cache in the disk controller.
  31.  *
  32.  *
  33.  * New editor name:  TDE, the Thomson-Davis Editor.
  34.  * Author:           Frank Davis
  35.  * Date:             June 5, 1991, version 1.0
  36.  * Date:             July 29, 1991, version 1.1
  37.  * Date:             October 5, 1991, version 1.2
  38.  * Date:             January 20, 1992, version 1.3
  39.  * Date:             February 17, 1992, version 1.4
  40.  * Date:             April 1, 1992, version 1.5
  41.  * Date:             June 5, 1992, version 2.0
  42.  * Date:             October 31, 1992, version 2.1
  43.  * Date:             April 1, 1993, version 2.2
  44.  * Date:             June 5, 1993, version 3.0
  45.  * Date:             August 29, 1993, version 3.1
  46.  * Date:             November 13, 1993, version 3.2
  47.  * Date:             June 5, 1994, version 4.0
  48.  *
  49.  * This code is released into the public domain, Frank Davis.
  50.  * You may distribute it freely.
  51.  */
  52.  
  53.  
  54. #include "tdestr.h"             /* tde types */
  55. #include "common.h"
  56. #include "define.h"
  57. #include "tdefunc.h"
  58.  
  59. #if !defined( __UNIX__ )
  60.  #include <dos.h>                /* for renaming files */
  61.  #include <bios.h>               /* for direct BIOS keyboard input */
  62.  #include <io.h>                 /* for file attribute code */
  63.  #if defined( __MSC__ )
  64.   #include <errno.h>
  65.   #include <sys\types.h>         /* S_IWRITE etc */
  66.  #endif
  67.  #include <sys\stat.h>           /* S_IWRITE etc */
  68. #endif
  69.  
  70. #include <fcntl.h>              /* open flags */
  71.  
  72. /*
  73.  * Name:    write_file
  74.  * Purpose: To write text to a file
  75.  *           way.
  76.  * Date:    June 5, 1991
  77.  * Passed:  name:  name of disk file or device
  78.  *          open_mode:  fopen flags to be used in open
  79.  *          file:  pointer to file structure to write
  80.  *          start: first node to write
  81.  *          end:   last node to write
  82.  *          block: write a file or a marked block
  83.  * Returns: OK, or ERROR if anything went wrong
  84.  */
  85. int  write_file( char *name, int open_mode, file_infos *file, long start,
  86.                  long end, int block )
  87. {
  88. FILE *fp;       /* file to be written */
  89. char *p;
  90. char *z = "\x1a";
  91. register int rc;
  92. int  bc;
  93. int  ec;
  94. int  len;
  95. int  write_z;
  96. int  write_eol;
  97. long number;
  98. line_list_ptr ll;
  99. char *open_string;
  100. char *eol;
  101. size_t eol_count;
  102.  
  103.    write_z = mode.control_z;
  104.    switch (open_mode) {
  105.       case APPEND :
  106.          open_string = "ab";
  107.          break;
  108.       case OVERWRITE :
  109.       default :
  110.          open_string = "wb";
  111.          break;
  112.    }
  113.    switch (file->crlf) {
  114.       case BINARY   :
  115.          eol_count = 0;
  116.          eol = "";
  117.          write_z = FALSE;
  118.          break;
  119.       case CRLF   :
  120.          eol_count = 2;
  121.          eol = "\r\n";
  122.          break;
  123.       case LF     :
  124.          eol_count = 1;
  125.          eol = "\n";
  126.          break;
  127.       default     :
  128.          eol_count = 0;
  129.          eol = "";
  130.          assert( FALSE );
  131.    }
  132.    rc = OK;
  133.    if ((fp = fopen( name, open_string )) == NULL || ceh.flag == ERROR)
  134.       rc = ERROR;
  135.    else {
  136.       ec = bc = len = 0;
  137.       ll = file->line_list;
  138.       if (block == LINE || block == BOX || block == STREAM) {
  139.          if (g_status.marked_file == NULL)
  140.             rc = ERROR;
  141.          else
  142.             file = g_status.marked_file;
  143.          if (rc != ERROR) {
  144.             ll = file->line_list;
  145.             for (number=1; number<start && ll->next != NULL; number++)
  146.                ll = ll->next;
  147.          }
  148.          if (rc != ERROR && (block == BOX || block == STREAM)) {
  149.             bc  = file->block_bc;
  150.             ec  = file->block_ec;
  151.             len = ec + 1 - bc;
  152.          }
  153.          if (rc != ERROR  &&  block == STREAM) {
  154.             if (start == end )
  155.                block = BOX;
  156.          }
  157.       } else {
  158.          for (number=1; number<start && ll->next != NULL; number++)
  159.             ll = ll->next;
  160.       }
  161.       p = g_status.line_buff;
  162.       if (rc == OK) {
  163.          if (block == BOX) {
  164.  
  165.             assert( len >= 0 );
  166.             assert( len < MAX_LINE_LENGTH );
  167.  
  168.             for (;start <= end  &&  ll->len != EOF && rc == OK; start++) {
  169.                g_status.copied = FALSE;
  170.                load_box_buff( p, ll, bc, ec, ' ' );
  171.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  172.                           ceh.flag == ERROR)
  173.                   rc = ERROR;
  174.                if ((rc != ERROR  &&
  175.                     fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count)
  176.                               || ceh.flag == ERROR)
  177.                   rc = ERROR;
  178.                ll = ll->next;
  179.                if (ll == NULL)
  180.                   rc = ERROR;
  181.             }
  182.          } else {
  183.             for (number=start; number <= end && rc == OK && ll->len != EOF;
  184.                       number++) {
  185.                g_status.copied = FALSE;
  186.                copy_line( ll );
  187.                len = g_status.line_buff_len;
  188.                if (block == STREAM) {
  189.                   if (number == start) {
  190.                      bc = bc > len ? len : bc;
  191.                      len = len - bc;
  192.  
  193.                      assert( len >= 0 );
  194.  
  195.                      memmove( p, p + bc, len );
  196.                   } else if (number == end) {
  197.                      ++ec;
  198.                      len =  ec > len ? len : ec;
  199.                   }
  200.                }
  201.  
  202.                assert( len >= 0 );
  203.                assert( len < MAX_LINE_LENGTH );
  204.  
  205.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  206.                        ceh.flag == ERROR)
  207.                   rc = ERROR;
  208.  
  209.                /*
  210.                 * if a Control-Z is already at EOF, don't write another one.
  211.                 */
  212.                write_eol = TRUE;
  213.                if (number == end) {
  214.                   if (file->crlf == CRLF ||  file->crlf == LF) {
  215.                      if (len > 0  &&  *(p + len - 1) == '\x1a') {
  216.                         write_eol = FALSE;
  217.                         write_z = FALSE;
  218.                      }
  219.                   }
  220.                }
  221.  
  222.                if ((write_eol == TRUE  &&  rc != ERROR  &&
  223.                      fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count)
  224.                      || ceh.flag == ERROR)
  225.                   rc = ERROR;
  226.                ll = ll->next;
  227.                if (ll == NULL)
  228.                   rc = ERROR;
  229.             }
  230.          }
  231.          if (rc != ERROR  &&  write_z) {
  232.             if (fwrite( z, sizeof( char ), 1, fp ) < 1 || ceh.flag == ERROR)
  233.                rc = ERROR;
  234.          }
  235.          g_status.copied = FALSE;
  236.          if (ceh.flag != ERROR) {
  237.             if (fclose( fp ) != 0)
  238.                rc = ERROR;
  239.          }
  240.       }
  241.    }
  242.    return( rc );
  243. }
  244.  
  245.  
  246. /*
  247.  * Name:    hw_save
  248.  * Purpose: To save text to a file
  249.  * Date:    November 11, 1989
  250.  * Passed:  name:  name of disk file
  251.  *          file:  pointer to file structure
  252.  *          start: first character in text buffer
  253.  *          end:   last character (+1) in text buffer
  254.  *          block: type of block defined
  255.  * Returns: OK, or ERROR if anything went wrong
  256.  */
  257. int hw_save( char *name, file_infos *file, long start, long end, int block )
  258. {
  259.    return( write_file( name, OVERWRITE, file, start, end, block ) );
  260. }
  261.  
  262.  
  263. /*
  264.  * Name:    hw_append
  265.  * Purpose: To append text to a file.
  266.  * Date:    November 11, 1989
  267.  * Passed:  name:  name of disk file
  268.  *          file:  pointer to file structure
  269.  *          start: first character in text buffer
  270.  *          end:   last character (+1) in text buffer
  271.  *          block: type of defined block
  272.  * Returns: OK, or ERROR if anything went wrong
  273.  */
  274. int hw_append( char *name, file_infos *file, long start, long end, int block )
  275. {
  276.    return( write_file( name, APPEND, file, start, end, block ) );
  277. }
  278.  
  279.  
  280. /*
  281.  * Name:    load_file
  282.  * Purpose: To load a file into the array of text pointers.
  283.  * Date:    December 1, 1992
  284.  * Passed:  name:       name of disk file
  285.  *          fp:         pointer to file structure
  286.  *          file_mode:  BINARY or TEXT
  287.  *          bin_len:    if opened in BINARY mode, length of node line
  288.  * Returns: OK, or ERROR if anything went wrong
  289.  */
  290. int  load_file( char *name, file_infos *fp, int *file_mode, int bin_len )
  291. {
  292. FILE *stream;                           /* stream to read */
  293. int  rc;
  294. text_ptr l;
  295. line_list_ptr ll;
  296. line_list_ptr temp_ll;
  297. unsigned long line_count;
  298. char *e;
  299. char *residue;
  300. int  len;
  301. int  res;
  302. size_t t1, t2;
  303. int  crlf;
  304. int  prompt_line;
  305. char temp[MAX_COLS+2];
  306. #if defined( __UNIX__ )
  307.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  308. #else
  309.  char display_buff[(MAX_COLS+2)*2];
  310. #endif
  311.  
  312.    /*
  313.     * initialize the counters and pointers
  314.     */
  315.    rc = OK;
  316.    len = 1;
  317.    line_count = 0;
  318.    res = 0;
  319.    residue = g_status.line_buff;
  320.    prompt_line = g_display.nlines;
  321.    fp->length  = 0;
  322.    fp->undo_count = 0;
  323.    fp->undo_top = fp->undo_bot = NULL;
  324.    fp->line_list_end = fp->line_list = NULL;
  325.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  326.  
  327.    if (ll != NULL) {
  328.       ll->dirty = FALSE;
  329.       ll->len   = EOF;
  330.       ll->line  = NULL;
  331.       ll->next  = ll->prev = NULL;
  332.       fp->undo_top = fp->undo_bot = ll;
  333.    }
  334.  
  335.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  336.  
  337.    if (ll != NULL) {
  338.       ll->dirty = FALSE;
  339.       ll->len   = EOF;
  340.       ll->line  = NULL;
  341.       ll->next  = ll->prev = NULL;
  342.       fp->line_list_end = fp->line_list = ll;
  343.    }
  344.  
  345.    if ((stream = fopen( name, "rb" )) == NULL || ceh.flag == ERROR ||
  346.          rc == ERROR) {
  347.       /*
  348.        * file not found or error loading file
  349.        */
  350.       combine_strings( temp, main7a, name, main7b );
  351.       save_screen_line( 0, prompt_line, display_buff );
  352.       set_prompt( temp, prompt_line );
  353.       getkey( );
  354.       restore_screen_line( 0, prompt_line, display_buff );
  355.       if (fp->line_list != NULL)
  356.          my_free( fp->line_list );
  357.       if (fp->undo_top != NULL)
  358.          my_free( fp->undo_top );
  359.       rc = ERROR;
  360.    } else {
  361.  
  362. #if defined( __UNIX__ )
  363.       g_status.line_buff[0] = g_status.line_buff[1] == '\0';
  364.       t1 = fread( g_status.line_buff, sizeof(char), 2, stream );
  365.       if (t1 == 2) {
  366.          if (g_status.line_buff[0] == '#' &&  g_status.line_buff[1] == '!')
  367.             *file_mode = TEXT;
  368.       }
  369.       fseek( stream, 0, SEEK_SET );
  370. #endif
  371.  
  372.       if (*file_mode == BINARY) {
  373.          mode.trailing = FALSE;
  374.          crlf = BINARY;
  375.          if (bin_len < 0  ||  bin_len > READ_LENGTH)
  376.             bin_len = DEFAULT_BIN_LENGTH;
  377.          for (; rc == OK;) {
  378.             t1 = fread( g_status.line_buff, sizeof(char), bin_len, stream );
  379.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  380.                combine_strings( temp, main9, name, "'" );
  381.                error( WARNING, prompt_line, temp );
  382.                rc = ERROR;
  383.             } else if (t1) {
  384.  
  385.                assert( t1 < MAX_LINE_LENGTH );
  386.  
  387.                l = (text_ptr)my_malloc( t1 * sizeof(char), &rc );
  388.                temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  389.  
  390.                if (rc != ERROR) {
  391.  
  392.                   /*
  393.                    * if everything is everything, copy from io buff to
  394.                    *   dynamic mem.
  395.                    */
  396.                   if (t1 > 0)
  397.                      my_memcpy( l, g_status.line_buff, t1 );
  398.  
  399.                   ++line_count;
  400.                   temp_ll->line = l;
  401.                   temp_ll->dirty = FALSE;
  402.                   temp_ll->len  = t1;
  403.                   insert_node( fp, ll, temp_ll );
  404.                   ll = temp_ll;
  405.                } else
  406.                   rc = show_file_2big( name, prompt_line, temp_ll, l );
  407.             } else
  408.                break;
  409.          }
  410.       } else {
  411.          crlf = LF;
  412.          for (; rc == OK;) {
  413.             t1 = fread( g_status.line_buff, sizeof(char), READ_LENGTH, stream );
  414.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  415.                combine_strings( temp, main9, name, "'" );
  416.                error( WARNING, prompt_line, temp );
  417.                rc = ERROR;
  418.             } else {
  419.  
  420.                /*
  421.                 * "e" walks down io buffer 1 looking for end of lines.  "t1"
  422.                 *   keeps count of number of characters in io buffer 1.
  423.                 */
  424.                e = g_status.line_buff;
  425.                while (t1 && rc == OK) {
  426.  
  427.                   /*
  428.                    * while "t1" is not zero and "len" is less than max line length,
  429.                    *   let "e" walk down the buffer until it find <LF>.
  430.                    */
  431.                   for (; t1 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t1--);
  432.  
  433.                   /*
  434.                    * if "t1" is not zero, we either found a <LF> or the line
  435.                    *   length max'd out.
  436.                    */
  437.                   if (t1  ||  len >= READ_LENGTH) {
  438.  
  439.                      if (len > 1 && *e == '\n') {
  440.                         if (len - res == 1) {
  441.                            if (*(residue + res - 1) == '\r') {
  442.                               --len;
  443.                               --res;
  444.                               crlf = CRLF;
  445.                            }
  446.                         } else {
  447.                            if (*(e - 1) == '\r') {
  448.                               --len;
  449.                               crlf = CRLF;
  450.                            }
  451.                         }
  452.                      }
  453.                      if (len > 0)
  454.                         --len;
  455.  
  456.                      assert( len >= 0 );
  457.                      assert( len < MAX_LINE_LENGTH );
  458.  
  459.                      /*
  460.                       * allocate space for relocatable array of line pointers and
  461.                       *   allocate space for the line we just read.
  462.                       */
  463.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  464.                      temp_ll =
  465.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  466.  
  467.                      if (rc != ERROR) {
  468.  
  469.                         /*
  470.                          * if everything is everything, copy from io buff to
  471.                          *   dynamic mem.  "residue" keeps up with the beginning
  472.                          *   of line in io buffer.
  473.                          */
  474.                         if (res > 0) {
  475.  
  476.                            assert( res >= 0 );
  477.                            assert( len - res >= 0 );
  478.  
  479.                            if (res > 0)
  480.                               my_memcpy( l, residue, res );
  481.                            if (len - res > 0)
  482.                               my_memcpy( l + res, g_status.line_buff, len - res );
  483.                            res = 0;
  484.                         } else
  485.                            if (len > 0)
  486.                               my_memcpy( l, residue, len );
  487.  
  488.                         ++line_count;
  489.                         temp_ll->line = l;
  490.                         temp_ll->dirty = FALSE;
  491.                         temp_ll->len  = len;
  492.                         insert_node( fp, ll, temp_ll );
  493.                         ll = temp_ll;
  494.  
  495.                         /*
  496.                          * reset io buffer pointers and counters.
  497.                          */
  498.                         if (t1 == 0)
  499.                            residue = g_status.tabout_buff;
  500.                         else {
  501.                            t1--;
  502.                            if (len + 1 < READ_LENGTH)
  503.                               residue =  t1 == 0 ? g_status.tabout_buff : ++e;
  504.                            else {
  505.                               if (*e != '\n') {
  506.                                  t1++;
  507.                                  residue = e;
  508.                               } else
  509.                                  residue =  t1 == 0 ? g_status.tabout_buff : ++e;
  510.                            }
  511.                         }
  512.                         len = 1;
  513.                      } else
  514.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  515.                   } else if (len < READ_LENGTH ) {
  516.                      if (!feof( stream ))
  517.                         res = len - 1;
  518.                   } else {
  519.                      error( WARNING, prompt_line, main9a );
  520.                      rc = ERROR;
  521.                   }
  522.                }
  523.             }
  524.  
  525.             if (rc != OK)
  526.                break;
  527.  
  528.             /*
  529.              * we may have read all lines that end in '\n', but there may
  530.              *   be some residue after the last '\n'.  ^Z is a good example.
  531.              */
  532.             if (feof( stream )) {
  533.                if (len > 1) {
  534.                   --len;
  535.                   if (t1 == 0)
  536.                      --e;
  537.  
  538.                   assert( len >= 0 );
  539.                   assert( len < MAX_LINE_LENGTH );
  540.  
  541.                   /*
  542.                    * allocate space for relocatable array of line pointers and
  543.                    *   allocate space for the line we just read.
  544.                    */
  545.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  546.                   temp_ll =
  547.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  548.  
  549.                   if (rc != ERROR) {
  550.  
  551.                      /*
  552.                       * if everything is everything, copy from io buff to
  553.                       *   dynamic mem.  "residue" keeps up with the beginning
  554.                       *   of line in io buffer.
  555.                       */
  556.                      if (res > 0) {
  557.  
  558.                         assert( res >= 0 );
  559.                         assert( res < MAX_LINE_LENGTH);
  560.                         assert( len - res >= 0 );
  561.                         assert( len - res < MAX_LINE_LENGTH);
  562.  
  563.                         if (res > 0 )
  564.                            my_memcpy( l, residue, res );
  565.                         if (len - res > 0)
  566.                            my_memcpy( l + res, g_status.line_buff, len - res );
  567.                      } else
  568.                         if (len > 0)
  569.                            my_memcpy( l, residue, len );
  570.                      ++line_count;
  571.                      temp_ll->line = l;
  572.                      temp_ll->dirty = FALSE;
  573.                      temp_ll->len  = len;
  574.                      insert_node( fp, ll, temp_ll );
  575.                   } else
  576.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  577.                }
  578.                break;
  579.             }
  580.  
  581.             t2 = fread( g_status.tabout_buff, sizeof(char), READ_LENGTH, stream );
  582.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  583.                combine_strings( temp, main9, name, "'" );
  584.                error( WARNING, prompt_line, temp );
  585.                rc = ERROR;
  586.             } else if (rc == OK) {
  587.                e = g_status.tabout_buff;
  588.                while (t2 && rc == OK) {
  589.                   for (; t2 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t2--);
  590.                   if (t2  ||  len >= READ_LENGTH) {
  591.  
  592.                      if (len > 1 && *e == '\n') {
  593.                         if (len - res == 1) {
  594.                            if (*(residue + res - 1) == '\r') {
  595.                               --len;
  596.                               --res;
  597.                               crlf = CRLF;
  598.                            }
  599.                         } else {
  600.                            if (*(e - 1) == '\r') {
  601.                               --len;
  602.                               crlf = CRLF;
  603.                            }
  604.                         }
  605.                      }
  606.                      if (len > 0)
  607.                         --len;
  608.  
  609.                      assert( len >= 0 );
  610.                      assert( len < MAX_LINE_LENGTH );
  611.  
  612.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  613.                      temp_ll =
  614.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  615.  
  616.                      if (rc != ERROR) {
  617.                         if (res > 0) {
  618.  
  619.                            assert( res >= 0 );
  620.                            assert( res < MAX_LINE_LENGTH);
  621.                            assert( len - res >= 0 );
  622.                            assert( len - res < MAX_LINE_LENGTH);
  623.  
  624.                            if (res > 0)
  625.                               my_memcpy( l, residue, res );
  626.                            if (len - res > 0)
  627.                               my_memcpy( l+res, g_status.tabout_buff, len - res );
  628.                            res = 0;
  629.                         } else
  630.                            if (len > 0)
  631.                               my_memcpy( l, residue, len );
  632.  
  633.                         ++line_count;
  634.                         temp_ll->line = l;
  635.                         temp_ll->dirty = FALSE;
  636.                         temp_ll->len  = len;
  637.                         insert_node( fp, ll, temp_ll );
  638.                         ll = temp_ll;
  639.  
  640.                         if (t2 == 0)
  641.                            residue = g_status.line_buff;
  642.                         else {
  643.                            t2--;
  644.                            if (len + 1 < READ_LENGTH)
  645.                               residue =  t2 == 0 ? g_status.line_buff : ++e;
  646.                            else {
  647.                               if (*e != '\n') {
  648.                                  t2++;
  649.                                  residue = e;
  650.                               } else
  651.                                  residue =  t2 == 0 ? g_status.line_buff : ++e;
  652.                            }
  653.                         }
  654.                         len = 1;
  655.                      } else
  656.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  657.                   } else if (len < READ_LENGTH) {
  658.                      if (!feof( stream ))
  659.                         res = len - 1;
  660.                   } else {
  661.                      error( WARNING, prompt_line, main9a );
  662.                      rc = ERROR;
  663.                   }
  664.                }
  665.             }
  666.  
  667.             if (rc != ERROR  &&  feof( stream )) {
  668.                if (len > 1) {
  669.                   --len;
  670.                   if (t2 == 0)
  671.                      --e;
  672.  
  673.                   assert( len >= 0 );
  674.                   assert( len < MAX_LINE_LENGTH );
  675.  
  676.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  677.                   temp_ll =
  678.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  679.  
  680.                   if (rc != ERROR) {
  681.                      if (res > 0) {
  682.  
  683.                         assert( res >= 0 );
  684.                         assert( res < MAX_LINE_LENGTH);
  685.                         assert( len - res >= 0 );
  686.                         assert( len - res < MAX_LINE_LENGTH);
  687.  
  688.                         if (res > 0)
  689.                            my_memcpy( l, residue, res );
  690.                         if (len - res > 0)
  691.                            my_memcpy( l+res, g_status.tabout_buff, len - res );
  692.                      } else
  693.                         if (len > 0)
  694.                            my_memcpy( l, residue, len );
  695.  
  696.                      ++line_count;
  697.                      temp_ll->line = l;
  698.                      temp_ll->dirty = FALSE;
  699.                      temp_ll->len  = len;
  700.                      insert_node( fp, ll, temp_ll );
  701.                   } else
  702.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  703.                }
  704.                break;
  705.             }
  706.          }
  707.          *file_mode = crlf;
  708.       }
  709.  
  710.       /*
  711.        * close the file
  712.        */
  713.       fp->length = line_count;
  714.    }
  715.    if (stream != NULL)
  716.       fclose( stream );
  717.    return( rc );
  718. }
  719.  
  720.  
  721. /*
  722.  * Name:    insert_node
  723.  * Purpose: To insert a node into a double linked list
  724.  * Date:    December 1, 1992
  725.  * Passed:  fp:  pointer to file structure that owns the double linked list
  726.  *          current: pointer to current node in double linked list
  727.  *          new:     pointer to new node to insert into double linked list
  728.  * Notes:   if the current list pointer is the last node in the list, insert
  729.  *            new code behind current node.
  730.  */
  731. void insert_node( file_infos *fp, line_list_ptr current, line_list_ptr new )
  732. {
  733.  
  734.    /*
  735.     * standard double linked list insert
  736.     */
  737.    if (current->next != NULL) {
  738.       current->next->prev = new;
  739.       new->next = current->next;
  740.       current->next = new;
  741.       new->prev = current;
  742.    /*
  743.     * if the current node is the NULL node, insert the new node behind current
  744.     */
  745.    } else {
  746.       new->next = current;
  747.       if (current->prev != NULL)
  748.          current->prev->next = new;
  749.       new->prev = current->prev;
  750.       current->prev = new;
  751.       if (new->prev == NULL)
  752.          fp->line_list = new;
  753.    }
  754. }
  755.  
  756.  
  757. /*
  758.  * Name:    show_file_2big
  759.  * Purpose: tell user we ran out of room loading file
  760.  * Date:    December 1, 1992
  761.  * Passed:  name:  name of disk file
  762.  *          line:  line to display messages
  763.  *          ll:    double linked list pointer
  764.  *          t:     text line pointer
  765.  * Returns: WARNING
  766.  * Notes:   one or both of the malloc requests overflowed the heap.  free the
  767.  *            dynamic if allocated.
  768.  */
  769. int  show_file_2big( char *name, int prompt_line, line_list_ptr ll, text_ptr t )
  770. {
  771. char temp[MAX_COLS+2];
  772.  
  773.    combine_strings( temp, main10a, name, main10b );
  774.    error( WARNING, prompt_line, temp );
  775.    if (t != NULL)
  776.       my_free( t );
  777.    if (ll != NULL)
  778.       my_free( ll );
  779.    return( WARNING );
  780. }
  781.  
  782.  
  783. /*
  784.  * Name:    backup_file
  785.  * Purpose: To make a back-up copy of current file.
  786.  * Date:    June 5, 1991
  787.  * Passed:  window:  current window pointer
  788.  */
  789. int  backup_file( TDE_WIN *window )
  790. {
  791. char *old_line_buff;
  792. char *old_tabout_buff;
  793. int  old_line_buff_len;
  794. int  old_tabout_buff_len;
  795. int  old_copied;
  796. int  rc;
  797. file_infos *file;
  798.  
  799.    rc = OK;
  800.    file = window->file_info;
  801.    if (file->backed_up == FALSE  &&  file->modified == TRUE) {
  802.       old_copied = g_status.copied;
  803.       old_line_buff_len = g_status.line_buff_len;
  804.       old_line_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  805.       old_tabout_buff_len = g_status.tabout_buff_len;
  806.       old_tabout_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  807.  
  808.       if (old_line_buff != NULL  &&  old_tabout_buff != NULL) {
  809.          memcpy( old_line_buff, g_status.line_buff, MAX_LINE_LENGTH );
  810.          memcpy( old_tabout_buff, g_status.tabout_buff, MAX_LINE_LENGTH );
  811.          if ((rc = save_backup( window )) != ERROR)
  812.             file->backed_up = TRUE;
  813.          else
  814.             rc = ERROR;
  815.          memcpy( g_status.line_buff, old_line_buff, MAX_LINE_LENGTH );
  816.          memcpy( g_status.tabout_buff, old_tabout_buff, MAX_LINE_LENGTH );
  817.          g_status.line_buff_len = old_line_buff_len;
  818.          g_status.tabout_buff_len = old_tabout_buff_len;
  819.          g_status.copied = old_copied;
  820.       } else {
  821.          error( WARNING, window->bottom_line, main4 );
  822.          rc = ERROR;
  823.       }
  824.       if (old_line_buff != NULL)
  825.          free( old_line_buff );
  826.       if (old_tabout_buff != NULL)
  827.          free( old_tabout_buff );
  828.    }
  829.    return( rc );
  830. }
  831.  
  832.  
  833. /*
  834.  * Name:    edit_file
  835.  * Purpose: To allocate space for a new file structure and set up some
  836.  *           of the relevant fields.
  837.  * Date:    June 5, 1991
  838.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  839.  * Passed:  name:  name of the file to edit
  840.  *          file_mode:  BINARY or TEXT
  841.  *          bin_length: if opened in BINARY mode, length of binary lines
  842.  * Returns: OK if file structure could be created
  843.  *          ERROR if out of memory
  844.  *
  845.  * Change:  file->next_letter is initialized to 0 instead 'a'
  846.  */
  847. int  edit_file( char *name, int file_mode, int bin_length )
  848. {
  849. int  rc;        /* return code */
  850. int  existing;
  851. int  line;
  852. int  rcol;
  853. register file_infos *file; /* file structure for file belonging to new window */
  854. file_infos *fp;
  855. long found_line;
  856. line_list_ptr ll;
  857. line_list_ptr temp_ll;
  858.  
  859.    line = g_display.nlines;
  860.    rc = OK;
  861.    /*
  862.     * allocate a file structure for the new file
  863.     */
  864.    file = (file_infos *)calloc( 1, sizeof(file_infos) );
  865.    if (file == NULL) {
  866.       error( WARNING, line, main4 );
  867.       rc = ERROR;
  868.    }
  869.    existing = FALSE;
  870.    if (rc == OK  &&  hw_fattrib( name ) == OK) {
  871.       existing = TRUE;
  872.       /*
  873.        * g_status.temp_end is set last character read in file
  874.        */
  875.  
  876.       if (g_status.command != DefineGrep  &&
  877.           g_status.command != DefineRegXGrep  &&
  878.           g_status.command != RepeatGrep)
  879.          rc = load_file( name, file, &file_mode, bin_length );
  880.       else {
  881.          if (g_status.sas_defined) {
  882.             rc = load_file( name, file, &file_mode, bin_length );
  883.             if (rc != ERROR) {
  884.                found_line = 1L;
  885.                rcol = 0;
  886.                if (g_status.sas_search_type == BOYER_MOORE)
  887.                   ll = search_forward( file->line_list, &found_line,
  888.                                        (size_t *)&rcol );
  889.                else
  890.                   ll = regx_search_forward( file->line_list, &found_line,
  891.                                             &rcol );
  892.                if (ll == NULL)
  893.                   rc = ERROR;
  894.                else {
  895.                   g_status.sas_rline = found_line;
  896.                   g_status.sas_rcol  = rcol;
  897.                   g_status.sas_ll    = ll;
  898.                }
  899.             }
  900.          } else
  901.             rc = ERROR;
  902.       }
  903.    } else {
  904.       if (ceh.flag == ERROR)
  905.          rc = ERROR;
  906.       else {
  907.          existing = FALSE;
  908.          file->length = 0l;
  909.          file->undo_top = file->undo_bot = NULL;
  910.          file->line_list_end = file->line_list = NULL;
  911.          file->undo_count = 0;
  912.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  913.          if (ll != NULL) {
  914.             ll->line  = NULL;
  915.             ll->next  = ll->prev = NULL;
  916.             ll->dirty = FALSE;
  917.             ll->len   = EOF;
  918.             file->undo_top = file->undo_bot = ll;
  919.          } else
  920.             rc = ERROR;
  921.  
  922.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  923.          if (ll != NULL) {
  924.             ll->line = NULL;
  925.             ll->next = ll->prev = NULL;
  926.             ll->dirty = FALSE;
  927.             ll->len   = EOF;
  928.             file->line_list_end = file->line_list = ll;
  929.          } else
  930.             rc = ERROR;
  931.          if (rc == ERROR) {
  932.             if (file->undo_top != NULL)
  933.                my_free( file->undo_top );
  934.             if (file->line_list != NULL)
  935.                my_free( file->line_list );
  936.          } else
  937.             if (file_mode == TEXT)
  938. #if defined( __UNIX__ )
  939.                file_mode = LF;
  940. #else
  941.                file_mode = CRLF;
  942. #endif
  943.       }
  944.    }
  945.  
  946.    if (rc != ERROR) {
  947.       /*
  948.        * add file into list
  949.        */
  950.       file->prev = NULL;
  951.       file->next = NULL;
  952.       if (g_status.file_list == NULL)
  953.          g_status.file_list = file;
  954.       else {
  955.          fp = g_status.current_file;
  956.          file->prev = fp;
  957.          if (fp->next)
  958.             fp->next->prev = file;
  959.          file->next = fp->next;
  960.          fp->next = file;
  961.       }
  962.  
  963.       /*
  964.        * set up all the info we need to know about a file.
  965.        */
  966.  
  967.       assert( file_mode == CRLF  ||  file_mode == LF  ||  file_mode == BINARY );
  968.       assert( strlen( name ) < (size_t)g_display.ncols );
  969.  
  970.       strcpy( file->file_name, name );
  971. #if defined( __UNIX__ )
  972.       get_fattr( name, &file->file_attrib );
  973. #else
  974.       get_fattr( name, (int *)&file->file_attrib );
  975. #endif
  976.       file->block_type  = NOTMARKED;
  977.       file->block_br    = file->block_er = 0l;
  978.       file->block_bc    = file->block_ec = 0;
  979.       file->ref_count   = 0;
  980.       file->modified    = FALSE;
  981.       file->backed_up   = FALSE;
  982.       file->new_file    = !existing;
  983.       file->next_letter = 0;
  984.       file->file_no     = ++g_status.file_count;
  985.       file->crlf        = file_mode;
  986.       g_status.current_file = file;
  987.       make_backup_fname( file );
  988.    } else if (file != NULL) {
  989.       /*
  990.        * free the line pointers and linked list of line pointers.
  991.        */
  992.       ll = file->undo_top;
  993.       while (ll != NULL) {
  994.          temp_ll = ll->next;
  995.          if (ll->line != NULL)
  996.             my_free( ll->line );
  997.          my_free( ll );
  998.          ll = temp_ll;
  999.       }
  1000.  
  1001.       ll = file->line_list;
  1002.       while (ll != NULL) {
  1003.          temp_ll = ll->next;
  1004.          if (ll->line != NULL)
  1005.             my_free( ll->line );
  1006.          my_free( ll );
  1007.          ll = temp_ll;
  1008.       }
  1009.  
  1010. #if defined( __MSC__ )
  1011.       _fheapmin( );
  1012. #endif
  1013.  
  1014.       free( file );
  1015.    }
  1016.    return( rc );
  1017. }
  1018.  
  1019.  
  1020. /*
  1021.  * Name:    edit_another_file
  1022.  * Purpose: Bring in another file to editor.
  1023.  * Date:    June 5, 1991
  1024.  * Passed:  window:  pointer to current window
  1025.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1026.  */
  1027. int  edit_another_file( TDE_WIN *window )
  1028. {
  1029. #if defined( __UNIX__ )
  1030.  char fname[PATH_MAX];          /* new name for file */
  1031.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  1032. #else
  1033.  char fname[MAX_COLS];          /* new name for file */
  1034.  char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  1035.  char spdir[_MAX_DIR];           /* splitpath dir buff */
  1036.  char spname[_MAX_FNAME];        /* splitpath fname buff */
  1037.  char spext[_MAX_EXT];           /* splitpath ext buff */
  1038.  char display_buff[(MAX_COLS+2)*2];
  1039. #endif
  1040. register TDE_WIN *win;           /* put window pointer in a register */
  1041. int  rc;
  1042. int  file_mode;
  1043. int  bin_length;
  1044.  
  1045.    win = window;
  1046.    entab_linebuff( );
  1047.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1048.       return( ERROR );
  1049.    /*
  1050.     * read in name, no default
  1051.     */
  1052.    fname[0] = '\0';
  1053.    /*
  1054.     * file name to edit
  1055.     */
  1056.    if ((rc = get_name( ed15, win->bottom_line, fname,
  1057.                  g_display.message_color )) == OK  &&  *fname != '\0') {
  1058.  
  1059. #if defined( __UNIX__ )
  1060.  
  1061.       assert( strlen( fname ) < PATH_MAX );
  1062.  
  1063.       /*
  1064.        * X_OK is defined in unistd.h and tests for execute permission
  1065.        */
  1066.       if (access( fname, X_OK ) != ERROR) {
  1067.          file_mode = BINARY;
  1068.          bin_length = g_status.file_chunk;
  1069.       } else {
  1070.          file_mode = TEXT;
  1071.          bin_length = 0;
  1072.       }
  1073. #else
  1074.  
  1075.       file_mode = TEXT;
  1076.       bin_length = 0;
  1077.  
  1078.       assert( strlen( fname ) < (size_t)g_display.ncols );
  1079.  
  1080.       _splitpath( fname, spdrive, spdir, spname, spext );
  1081.       if (stricmp( spext, ".exe" ) == 0  ||  stricmp( spext, ".com" ) == 0) {
  1082.          file_mode = BINARY;
  1083.          bin_length = g_status.file_chunk;
  1084.       } else if (g_status.file_mode == BINARY) {
  1085.          save_screen_line( 0, win->bottom_line, display_buff );
  1086.          /*
  1087.           * open file in BINARY mode (y/n)
  1088.           */
  1089.          set_prompt( ed18, win->bottom_line );
  1090.          if (get_yn( ) == A_YES) {
  1091.             file_mode = BINARY;
  1092.             bin_length = g_status.file_chunk;
  1093.          }
  1094.          restore_screen_line( 0, win->bottom_line, display_buff );
  1095.       }
  1096. #endif
  1097.       rc = attempt_edit_display( fname, LOCAL, file_mode, bin_length );
  1098.       if (rc == OK)
  1099.          show_avail_mem( );
  1100.    }
  1101.    return( rc );
  1102. }
  1103.  
  1104.  
  1105. /*
  1106.  * Name:    attempt_edit_display
  1107.  * Purpose: try to load then display a file
  1108.  * Date:    June 5, 1991
  1109.  * Passed:  fname:       file name to load
  1110.  *          update_type: update current window or entire screen
  1111.  *          file_mode:   BINARY or TEXT
  1112.  *          bin_len:     if opened in BINARY mode, length of binary lines
  1113.  * Notes:   When we first start the editor, we need to update the entire
  1114.  *          screen.  When we load in a new file, we only need to update
  1115.  *          the current window.
  1116.  */
  1117. int  attempt_edit_display( char *fname, int update_type, int file_mode,
  1118.                            int bin_len )
  1119. {
  1120. register int rc;
  1121. TDE_WIN *win;
  1122.  
  1123.    rc = edit_file( fname, file_mode, bin_len );
  1124.    if (rc != ERROR) {
  1125.       rc = initialize_window( );
  1126.       if (rc != ERROR) {
  1127.          win = g_status.current_window;
  1128.          if (update_type == LOCAL) {
  1129.             if (g_status.command != DefineGrep  &&
  1130.                         g_status.command != DefineRegXGrep  &&
  1131.                         g_status.command != RepeatGrep)
  1132.                redraw_current_window( win );
  1133.             show_file_count( g_status.file_count );
  1134.             show_window_count( g_status.window_count );
  1135.             show_avail_mem( );
  1136.          } else if (update_type == GLOBAL)
  1137.             redraw_screen( win );
  1138.          if (win->file_info->new_file) {
  1139.             g_status.command = AddLine;
  1140.             insert_newline( win );
  1141.             win->file_info->modified = FALSE;
  1142.          }
  1143.       }
  1144.    }
  1145.    return( rc );
  1146. }
  1147.  
  1148.  
  1149. /*
  1150.  * Name:    file_file
  1151.  * Purpose: To file the current file to disk.
  1152.  * Date:    September 17, 1991
  1153.  * Passed:  window:  pointer to current window
  1154.  */
  1155. int  file_file( TDE_WIN *window )
  1156. {
  1157.    if (save_file( window ) == OK)
  1158.       finish( window );
  1159.    return( OK );
  1160. }
  1161.  
  1162.  
  1163. /*
  1164.  * Name:    save_file
  1165.  * Purpose: To save the current file to disk.
  1166.  * Date:    June 5, 1991
  1167.  * Passed:  window:  pointer to current window
  1168.  * Notes:   If anything goes wrong, then the modified flag is set.
  1169.  *          If the file is saved successfully, then modified flag is
  1170.  *           cleared.
  1171.  */
  1172. int  save_file( TDE_WIN *window )
  1173. {
  1174. register file_infos *file;
  1175. int  rc;
  1176. line_list_ptr temp_ll;
  1177. #if defined( __UNIX__ )
  1178.  char temp[PATH_MAX+2];
  1179. #else
  1180.  char temp[MAX_COLS+2];
  1181. #endif
  1182.  
  1183.    entab_linebuff( );
  1184.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1185.       return( ERROR );
  1186.    file = window->file_info;
  1187.    if (file->modified == FALSE)
  1188.       return( OK );
  1189.    /*
  1190.     * set up file name
  1191.     */
  1192. #if defined( __UNIX__ )
  1193.    assert( strlen( file->file_name ) < PATH_MAX );
  1194. #else
  1195.    assert( strlen( file->file_name ) < (size_t)g_display.ncols );
  1196. #endif
  1197.  
  1198.    strcpy( temp, file->file_name );
  1199.  
  1200.    /*
  1201.     * see if there was a file name - if not, then make the user
  1202.     *  supply one.
  1203.     */
  1204.    if (strlen( temp ) == 0)
  1205.       rc = save_as_file( window );
  1206.    else {
  1207.       /*
  1208.        * save the file
  1209.        */
  1210.       rc = write_to_disk( window, temp );
  1211.       if (rc != ERROR) {
  1212.          file->modified = FALSE;
  1213.          file->new_file = FALSE;
  1214.       }
  1215.    }
  1216.  
  1217.    /*
  1218.     * clear the dirty flags
  1219.     */
  1220.    if (rc == OK) {
  1221.       temp_ll = window->file_info->line_list;
  1222.       for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1223.          temp_ll->dirty = FALSE;
  1224.       window->file_info->dirty = GLOBAL;
  1225.    }
  1226.  
  1227.    return( rc );
  1228. }
  1229.  
  1230.  
  1231. /*
  1232.  * Name:    save_backup
  1233.  * Purpose: To save a backup copy of the current file to disk.
  1234.  * Date:    June 5, 1991
  1235.  * Passed:  window:  pointer to current window
  1236.  */
  1237. int  save_backup( TDE_WIN *window )
  1238. {
  1239.    /*
  1240.     * set up file name
  1241.     */
  1242.    return( write_to_disk( window, window->file_info->backup_fname ) );
  1243. }
  1244.  
  1245.  
  1246. /*
  1247.  * Name:    save_as_file
  1248.  * Purpose: To save the current file to disk, but under a new name.
  1249.  * Date:    June 5, 1991
  1250.  * Passed:  window:  pointer to current window
  1251.  */
  1252. int  save_as_file( TDE_WIN *window )
  1253. {
  1254. int  prompt_line;
  1255. int  rc;
  1256. register TDE_WIN *win;           /* put window pointer in a register */
  1257. line_list_ptr temp_ll;
  1258. #if defined( __UNIX__ )
  1259.  char answer[PATH_MAX+2];
  1260.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  1261.  mode_t fattr;
  1262. #else
  1263.  char answer[MAX_COLS+2];
  1264.  char display_buff[(MAX_COLS+2)*2];
  1265.  int  fattr;
  1266. #endif
  1267.  
  1268.    win = window;
  1269.    entab_linebuff( );
  1270.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1271.       return( ERROR );
  1272.    /*
  1273.     * read in name
  1274.     */
  1275.    prompt_line = win->bottom_line;
  1276.    save_screen_line( 0, prompt_line, display_buff );
  1277.  
  1278.    answer[0] = '\0';
  1279.    /*
  1280.     * new file name:
  1281.     */
  1282.    if ((rc = get_name( utils9, prompt_line, answer,
  1283.                 g_display.message_color )) == OK  &&  *answer != '\0') {
  1284.  
  1285. #if defined( __UNIX__ )
  1286.        /*
  1287.         * make sure it is OK to overwrite any existing file
  1288.         */
  1289.       rc = get_fattr( answer, &fattr );
  1290.       if (rc == OK) {
  1291.  
  1292.          /*
  1293.           * file exists. make sure this is a regular file, first
  1294.           */
  1295.          if (S_ISREG( fattr )) {
  1296.             /*
  1297.              * overwrite existing file?
  1298.              */
  1299.             set_prompt( utils10, prompt_line );
  1300.             if (get_yn( ) != A_YES  ||
  1301.                            change_mode( answer, prompt_line ) == ERROR)
  1302.                rc = ERROR;
  1303.          } else
  1304.             rc = ERROR;
  1305.       } else
  1306.          /*
  1307.           * file name does not exist. take a chance on a valid file name.
  1308.           */
  1309.          rc = OK;
  1310.  
  1311.       if (rc != ERROR)
  1312.          rc = write_to_disk( win, answer );
  1313. #else
  1314.        /*
  1315.         * make sure it is OK to overwrite any existing file
  1316.         */
  1317.       rc = get_fattr( answer, &fattr );
  1318.       if (rc == OK) {   /* file exists */
  1319.          /*
  1320.           * overwrite existing file?
  1321.           */
  1322.          set_prompt( utils10, prompt_line );
  1323.          if (get_yn( ) != A_YES  ||
  1324.                         change_mode( answer, prompt_line ) == ERROR)
  1325.             rc = ERROR;
  1326.       }
  1327.       if (rc != ERROR)
  1328.          rc = write_to_disk( win, answer );
  1329. #endif
  1330.  
  1331.       /*
  1332.        * depending on personal taste, you may want to uncomment the next
  1333.        *  lines to clear the dirty flags.
  1334.        */
  1335. /*
  1336.  *     if (rc == OK) {
  1337.  *        temp_ll = window->file_info->line_list;
  1338.  *        for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1339.  *           temp_ll->dirty = FALSE;
  1340.  *        window->file_info->dirty = GLOBAL;
  1341.  *     }
  1342.  */
  1343.    }
  1344.    restore_screen_line( 0, prompt_line, display_buff );
  1345.    return( rc );
  1346. }
  1347.  
  1348.  
  1349. #if defined( __UNIX__ )
  1350. /*
  1351.  **********************************************************************
  1352.  ******************************  PART 1  ******************************
  1353.  **********************************************************************
  1354.  *
  1355.  * Let's try to make unix have the look and feel of a PC.
  1356.  */
  1357.  
  1358.  
  1359. /*
  1360.  * Name:    make_backup_fname
  1361.  * Purpose: insert a .bak to back of UNIX file name
  1362.  * Date:    November 13, 1993
  1363.  * Passed:  file: information allowing access to the current file
  1364.  */
  1365. void make_backup_fname( file_infos *file )
  1366. {
  1367. char *p;
  1368. int  i;
  1369. int  len;
  1370. char temp[PATH_MAX+2];
  1371.  
  1372.    /*
  1373.     * if this is a new file then don't create a backup - can't backup
  1374.     *   a nonexisting file.
  1375.     */
  1376.    if (file->new_file)
  1377.       file->backed_up = TRUE;
  1378.  
  1379.    /*
  1380.     * find the file name extension if it exists
  1381.     */
  1382.    else {
  1383.       assert( strlen( file->file_name ) < PATH_MAX );
  1384.  
  1385.       strcpy( temp, file->file_name );
  1386.       len = strlen( temp );
  1387.       for (i=len, p=temp + len; i>=0; i--) {
  1388.  
  1389.          /*
  1390.           * we found the '.' extension character.  get out
  1391.           */
  1392.          if (*p == '.')
  1393.             break;
  1394.  
  1395.          /*
  1396.           * we're at the beginning of the string -  no directory char was
  1397.           *  found.  set the pointer to the beginning of file name string.
  1398.           */
  1399.          else if (i == 0) {
  1400.             p = temp + len;
  1401.             break;
  1402.          } else if (*p == '/') {
  1403.             /*
  1404.              * we found the directory character.
  1405.              */
  1406.             p = temp + len;
  1407.             break;
  1408.          }
  1409.          --p;
  1410.       }
  1411.  
  1412.       assert( strlen( temp ) + 5 < PATH_MAX );
  1413.  
  1414.       strcpy( p, ".bak" );
  1415.       strcpy( file->backup_fname, temp );
  1416.    }
  1417. }
  1418.  
  1419.  
  1420. /*
  1421.  * Name:    write_to_disk
  1422.  * Purpose: To write file from memory to disk
  1423.  * Date:    November 13, 1993
  1424.  * Passed:  window:  pointer to current window
  1425.  *          fname:   file name to save on disk
  1426.  */
  1427. int  write_to_disk( TDE_WIN *window, char *fname )
  1428. {
  1429. register file_infos *file;
  1430. int  rc;
  1431. int  prompt_line;
  1432. char temp[MAX_COLS+2];
  1433. char answer[PATH_MAX+2];
  1434. mode_t fattr;
  1435. chtype display_buff[MAX_COLS+2];        /* chtype is defined in curses.h */
  1436.  
  1437.    file = window->file_info;
  1438.    prompt_line = window->bottom_line;
  1439.  
  1440.    /*
  1441.     * set up file name
  1442.     */
  1443.    assert( strlen( fname ) < PATH_MAX );
  1444.  
  1445.    strcpy( answer, fname );
  1446.    save_screen_line( 0, prompt_line, display_buff );
  1447.    eol_clear( 0, prompt_line, g_display.message_color );
  1448.  
  1449.    /*
  1450.     * saving
  1451.     */
  1452.    if (strlen( answer ) > 50 )
  1453.       answer[50] ='\0';
  1454.    combine_strings( temp, utils6, answer, "'" );
  1455.    s_output( temp, prompt_line, 0, g_display.message_color );
  1456.    strcpy( answer, fname );
  1457.    if ((rc = hw_save( answer, file, 1L, file->length, NOTMARKED )) == ERROR) {
  1458.       if (ceh.flag != ERROR) {
  1459.          if (get_fattr( answer, &fattr ) == OK &&
  1460.                                     !(fattr & (S_IWUSR | S_IWGRP | S_IWOTH)))
  1461.             /*
  1462.              * file is read only
  1463.              */
  1464.             combine_strings( temp, utils7a, answer, utils7b );
  1465.          else
  1466.             /*
  1467.              * cannot write to
  1468.              */
  1469.             combine_strings( temp, utils8, answer, "'" );
  1470.          error( WARNING, prompt_line, temp );
  1471.       }
  1472.    }
  1473.    restore_screen_line( 0, prompt_line, display_buff );
  1474.    return( rc );
  1475. }
  1476.  
  1477.  
  1478. /*
  1479.  * Name:    search_and_seize
  1480.  * Purpose: search files for a pattern
  1481.  * Date:    November 13, 1993
  1482.  * Passed:  window:  pointer to current window
  1483.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1484.  */
  1485. int  search_and_seize( TDE_WIN *window )
  1486. {
  1487. char name[PATH_MAX];            /* new name for file */
  1488. char temp[PATH_MAX];            /* new name for file */
  1489. char *eos;
  1490. char searching[MAX_COLS];       /* buffer for displaying file name */
  1491. int  file_mode;
  1492. mode_t file_attr;
  1493. UNIX_DTA unix_dta;
  1494. struct stat fstat;
  1495. int  bin_length;
  1496. int  i;
  1497. int  update_type;
  1498. char *tokens;
  1499. register int rc = ERROR;
  1500. register TDE_WIN *win;           /* put window pointer in a register */
  1501. int  bottom_line;
  1502. chtype display_buff[MAX_COLS+2];
  1503.  
  1504.    win = window;
  1505.    update_type = win == NULL ? GLOBAL : LOCAL;
  1506.    if (update_type == LOCAL) {
  1507.       if (!g_status.sas_defined ||  g_status.command == DefineGrep ||
  1508.                               g_status.command == DefineRegXGrep) {
  1509.  
  1510.          /*
  1511.           * prompt for the search pattern and the seize path.
  1512.           *   initialize all this stuff.
  1513.           */
  1514.          if (g_status.command == DefineGrep)
  1515.             g_status.sas_search_type = BOYER_MOORE;
  1516.          else
  1517.             g_status.sas_search_type = REG_EXPRESSION;
  1518.  
  1519.          if (g_status.sas_search_type == BOYER_MOORE) {
  1520.             *sas_bm.pattern = '\0';
  1521.             if (get_name( win16a, win->bottom_line, (char *)sas_bm.pattern,
  1522.                              g_display.message_color ) == ERROR)
  1523.                return( ERROR );
  1524.             if (*sas_bm.pattern == '\0')
  1525.                return( ERROR );
  1526.          } else {
  1527.             *sas_regx.pattern = '\0';
  1528.             if (get_name( win16b, win->bottom_line, (char *)sas_regx.pattern,
  1529.                              g_display.message_color ) == ERROR)
  1530.                return( ERROR );
  1531.             if (*sas_regx.pattern == '\0')
  1532.                return( ERROR );
  1533.             else
  1534.                strcpy( (char *)regx.pattern, (char *)sas_regx.pattern );
  1535.          }
  1536.          *g_status.sas_tokens = '\0';
  1537.          if (get_name( win17, win->bottom_line, g_status.sas_tokens,
  1538.                           g_display.message_color ) == ERROR)
  1539.             return( ERROR );
  1540.          i = 0;
  1541.          tokens = strtok( g_status.sas_tokens, SAS_DELIMITERS );
  1542.          while (tokens != NULL) {
  1543.             g_status.sas_arg_pointers[i++] = tokens;
  1544.             tokens = strtok( NULL, SAS_DELIMITERS );
  1545.          }
  1546.          if (i == 0)
  1547.             return( ERROR );
  1548.          g_status.sas_arg_pointers[i] = NULL;
  1549.          g_status.sas_argc = i;
  1550.          g_status.sas_arg = 0;
  1551.          g_status.sas_argv = g_status.sas_arg_pointers;
  1552.          g_status.sas_found_first = FALSE;
  1553.          if (g_status.command == DefineGrep) {
  1554.             g_status.sas_defined = TRUE;
  1555.             bm.search_defined = sas_bm.search_defined = OK;
  1556.             build_boyer_array( );
  1557.          } else {
  1558.             i = build_nfa( );
  1559.             if (i == OK) {
  1560.                g_status.sas_defined = TRUE;
  1561.                regx.search_defined = sas_regx.search_defined = OK;
  1562.             } else
  1563.                g_status.sas_defined = FALSE;
  1564.          }
  1565.       }
  1566.       bottom_line = win->bottom_line;
  1567.    } else
  1568.       bottom_line = g_display.nlines;
  1569.    if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1570.       if (win != NULL) {
  1571.          entab_linebuff( );
  1572.          un_copy_line( win->ll, win, TRUE );
  1573.       }
  1574.  
  1575.       /*
  1576.        * while we haven't found a valid file, search thru the command
  1577.        * line path.
  1578.        * we may have an invalid file name when we finish matching all
  1579.        * files according to a pattern.  then, we need to go to the next
  1580.        * command line argument if it exists.
  1581.        */
  1582.       while (rc == ERROR && g_status.sas_arg < g_status.sas_argc) {
  1583.  
  1584.          /*
  1585.           * if we haven't starting searching for a file, check to see if
  1586.           * the file is a valid file name.  if no file is found, then let's
  1587.           * see if we can find according to a search pattern.
  1588.           */
  1589.          if (g_status.sas_found_first == FALSE) {
  1590.  
  1591.             assert( strlen( g_status.sas_argv[g_status.sas_arg] )
  1592.                         < PATH_MAX );
  1593.  
  1594.             strcpy( name, g_status.sas_argv[g_status.sas_arg] );
  1595.             rc = get_fattr( name, &file_attr );
  1596.  
  1597.             /*
  1598.              * file exists.
  1599.              */
  1600.             if (rc == OK)
  1601.                ++g_status.sas_arg;
  1602.  
  1603.             /*
  1604.              * if we get this far, we may have a path name.
  1605.              */
  1606.             else if (rc != ERROR) {
  1607.  
  1608.                rc = OK;
  1609.                if ((g_status.sas_dp = opendir( name )) == NULL)
  1610.                   rc = ERROR;
  1611.                else {
  1612.  
  1613.                   /*
  1614.                    * eos == end of stem
  1615.                    */
  1616.                   strcpy( temp, name );
  1617.                   i = strlen( temp );
  1618.                   if (temp[i-1] != '/')
  1619.                      strcat( temp, "/" );
  1620.                   eos = temp + strlen( temp );
  1621.  
  1622.                   while ((rc = my_findnext( g_status.sas_dp, &unix_dta )) == OK) {
  1623.                      strcpy( eos, unix_dta.fname );
  1624.                      if (stat( eos, &fstat ) >= 0  && S_ISREG( fstat.st_mode ))
  1625.                         break;
  1626.                   }
  1627.                   if (rc == ERROR) {
  1628.                      closedir( g_status.sas_dp );
  1629.                      g_status.sas_dp = NULL;
  1630.                   }
  1631.                }
  1632.  
  1633.                /*
  1634.                 * if we found a file using wildcard characters,
  1635.                 * set the g_status.sas_found_first flag to true so we can
  1636.                 * find the next matching file.  we need to save the
  1637.                 * pathname stem so we know which directory we are working in.
  1638.                 */
  1639.                if (rc == OK) {
  1640.                   g_status.found_first = TRUE;
  1641.  
  1642.                   assert( strlen( temp ) < PATH_MAX );
  1643.  
  1644.                   strcpy( name, temp );
  1645.  
  1646.                   /*
  1647.                    * g_status.sas_path includes the '/' at end of path
  1648.                    */
  1649.                   *eos = '\0';
  1650.                   strcpy( g_status.sas_path, temp );
  1651.                } else {
  1652.                   ++g_status.sas_arg;
  1653.                   if (win != NULL)
  1654.                      /*
  1655.                       * invalid path or file name
  1656.                       */
  1657.                      error( WARNING, win->bottom_line, win8 );
  1658.                }
  1659.             } else if (rc == ERROR)
  1660.                ++g_status.sas_arg;
  1661.          } else {
  1662.  
  1663.             /*
  1664.              * we already found one file with wild card characters,
  1665.              * find the next matching file.
  1666.              */
  1667.             strcpy( temp, g_status.sas_path );
  1668.             eos = temp + strlen( temp );
  1669.  
  1670.             while ((rc = my_findnext( g_status.sas_dp, &unix_dta )) == OK) {
  1671.                strcpy( eos, unix_dta.fname );
  1672.                if (stat( eos, &fstat ) >= 0  &&  S_ISREG( fstat.st_mode ))
  1673.                   break;
  1674.             }
  1675.  
  1676.             if (rc == OK) {
  1677.  
  1678.                assert( strlen( temp ) < PATH_MAX );
  1679.  
  1680.                strcpy( name, temp );
  1681.             } else {
  1682.                g_status.sas_found_first = FALSE;
  1683.                ++g_status.sas_arg;
  1684.                if (g_status.sas_dp != NULL)
  1685.                   closedir( g_status.sas_dp );
  1686.             }
  1687.          }
  1688.  
  1689.          /*
  1690.           * if everything is everything so far, set up the file
  1691.           * and window structures and bring the file into the editor.
  1692.           */
  1693.          if (rc == OK) {
  1694.  
  1695.             assert( strlen( win19 ) + strlen( name ) < g_display.ncols );
  1696.  
  1697.             strcpy( searching, win19 );
  1698. /*            strcpy( temp, unix_dta.fname );   */
  1699.             strcpy( temp, name );
  1700.             if (strlen( temp ) > 50)
  1701.                temp[50] = '\0';
  1702.             strcat( searching, temp );
  1703.             save_screen_line( 0, bottom_line, display_buff );
  1704.             set_prompt( searching, bottom_line );
  1705.             refresh( );
  1706.             file_mode = TEXT;
  1707.             bin_length = 0;
  1708.  
  1709.             assert( strlen( name ) < PATH_MAX );
  1710.  
  1711.             if (access( name, X_OK ) != ERROR) {
  1712.                file_mode = BINARY;
  1713.                bin_length = g_status.file_chunk;
  1714.             }
  1715.  
  1716.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1717.             if (rc == OK)
  1718.                show_avail_mem( );
  1719.             restore_screen_line( 0, bottom_line, display_buff );
  1720.  
  1721.             if (rc == OK) {
  1722.                win = g_status.current_window;
  1723.                bin_offset_adjust( win, g_status.sas_rline );
  1724.                find_adjust( win, g_status.sas_ll, g_status.sas_rline,
  1725.                             g_status.sas_rcol );
  1726.                make_ruler( win );
  1727.                show_ruler( win );
  1728.                show_ruler_pointer( win );
  1729.                show_window_header( win );
  1730.                if (win->vertical)
  1731.                   show_vertical_separator( win );
  1732.                win->file_info->dirty = LOCAL;
  1733.             }
  1734.          }
  1735.  
  1736.          /*
  1737.           * either there are no more matching files or we had an
  1738.           * invalid file name, set rc to ERROR and let's look at the
  1739.           * next file name or pattern on the command line.
  1740.           */
  1741.          else
  1742.             rc = ERROR;
  1743.       }
  1744.    }
  1745.    if (rc == ERROR &&  g_status.sas_arg >= g_status.sas_argc  && win != NULL)
  1746.       /*
  1747.        * no more files to load
  1748.        */
  1749.       error( WARNING, win->bottom_line, win9 );
  1750.    return( rc );
  1751. }
  1752.  
  1753.  
  1754. /*
  1755.  * Name:    edit_next_file
  1756.  * Purpose: edit next file on command line.
  1757.  * Date:    November 13, 1993
  1758.  * Passed:  window:  pointer to current window
  1759.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1760.  */
  1761. int  edit_next_file( TDE_WIN *window )
  1762. {
  1763. char name[PATH_MAX+2];  /* new name for file */
  1764. char temp[PATH_MAX+2];  /* temp for new name for file */
  1765. char *eos;              /* end of string */
  1766. mode_t  file_type;
  1767. UNIX_DTA unix_dta;
  1768. struct stat fstat;
  1769. int  file_mode;
  1770. int  bin_length;
  1771. int  i;
  1772. int  update_type;
  1773. register int rc = ERROR;
  1774. register TDE_WIN *win;           /* put window pointer in a register */
  1775.  
  1776.    win = window;
  1777.    update_type = win == NULL ? GLOBAL : LOCAL;
  1778.    if (g_status.arg < g_status.argc) {
  1779.       if (win != NULL) {
  1780.          entab_linebuff( );
  1781.          if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1782.             return( ERROR );
  1783.       }
  1784.  
  1785.       /*
  1786.        * while we haven't found a valid file, search thru the command
  1787.        * line path.
  1788.        * we may have an invalid file name when we finish matching all
  1789.        * files according to a pattern.  then, we need to go to the next
  1790.        * command line argument if it exists.
  1791.        */
  1792.       while (rc == ERROR && g_status.arg < g_status.argc) {
  1793.  
  1794.          /*
  1795.           * if we haven't starting searching for a file, check to see if
  1796.           * the file is a valid file name.  if no file is found, then let's
  1797.           * see if we can find according to a search pattern.
  1798.           */
  1799.          if (g_status.found_first == FALSE) {
  1800.  
  1801.             assert( strlen( g_status.argv[g_status.arg] ) < PATH_MAX );
  1802.  
  1803.             strcpy( name, g_status.argv[g_status.arg] );
  1804.             rc = get_fattr( name, &file_type );
  1805.  
  1806.             /*
  1807.              * file exists
  1808.              */
  1809.             if (rc == OK)
  1810.                ++g_status.arg;
  1811.  
  1812.             /*
  1813.              * if we get this far, we may have a path name.
  1814.              */
  1815.             else {
  1816.  
  1817.                rc = OK;
  1818.  
  1819.                /*
  1820.                 * try to open arg as a directory name.
  1821.                 */
  1822.                if ((g_status.dp = opendir( name )) == NULL) {
  1823.  
  1824.                   /*
  1825.                    * failed as a directory name.  now, try to open a new file
  1826.                    */
  1827.                   ++g_status.arg;
  1828.                } else {
  1829.  
  1830.                   /*
  1831.                    * eos == end of stem
  1832.                    */
  1833.                   strcpy( temp, name );
  1834.                   i = strlen( temp );
  1835.                   if (temp[i-1] != '/')
  1836.                      strcat( temp, "/" );
  1837.                   eos = temp + strlen( temp );
  1838.  
  1839.                   while ((rc = my_findnext( g_status.dp, &unix_dta )) == OK) {
  1840.                      strcpy( eos, unix_dta.fname );
  1841.                      if (stat( eos, &fstat ) >= 0  && S_ISREG( fstat.st_mode ))
  1842.                         break;
  1843.                   }
  1844.                   if (rc == ERROR) {
  1845.                      closedir( g_status.dp );
  1846.                      g_status.dp = NULL;
  1847.                      ++g_status.arg;
  1848.                      if (win != NULL)
  1849.                         /*
  1850.                          * invalid path or file name
  1851.                          */
  1852.                         error( WARNING, win->bottom_line, win8 );
  1853.                   } else {
  1854.  
  1855.                   /*
  1856.                    * if we found a file using wildcard characters,
  1857.                    * set the g_status.found_first flag to true so we can
  1858.                    * find the next matching file.  we need to save the
  1859.                    * pathname stem so we know which directory we are working in.
  1860.                    */
  1861.                      g_status.found_first = TRUE;
  1862.  
  1863.                      assert( strlen( temp ) < PATH_MAX );
  1864.  
  1865.                      strcpy( name, temp );
  1866.  
  1867.                      /*
  1868.                       * g_status.path includes the '/' at end of path
  1869.                       */
  1870.                      *eos = '\0';
  1871.                      strcpy( g_status.path, temp );
  1872.                   }
  1873.                }
  1874.             }
  1875.          } else {
  1876.  
  1877.             /*
  1878.              * we already found one file with wild card characters,
  1879.              * find the next matching file.
  1880.              */
  1881.             strcpy( temp, g_status.path );
  1882.             eos = temp + strlen( temp );
  1883.  
  1884.             while ((rc = my_findnext( g_status.dp, &unix_dta )) == OK) {
  1885.                strcpy( eos, unix_dta.fname );
  1886.                if (stat( eos, &fstat ) >= 0  &&  S_ISREG( fstat.st_mode ))
  1887.                   break;
  1888.             }
  1889.  
  1890.             if (rc == OK) {
  1891.  
  1892.                assert( strlen( temp ) < PATH_MAX );
  1893.  
  1894.                strcpy( name, temp );
  1895.             } else {
  1896.                g_status.found_first = FALSE;
  1897.                ++g_status.arg;
  1898.                if (g_status.dp != NULL)
  1899.                   closedir( g_status.dp );
  1900.             }
  1901.          }
  1902.  
  1903.          /*
  1904.           * if everything is everything so far, set up the file
  1905.           * and window structures and bring the file into the editor.
  1906.           */
  1907.          if (rc == OK) {
  1908.             file_mode = g_status.file_mode;
  1909.             bin_length = g_status.file_chunk;
  1910.  
  1911.             assert( strlen( name ) < PATH_MAX );
  1912.  
  1913.             if (access( name, X_OK ) != ERROR) {
  1914.                file_mode = BINARY;
  1915.                bin_length = g_status.file_chunk;
  1916.             }
  1917.  
  1918.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1919.             if (rc == OK)
  1920.                show_avail_mem( );
  1921.          }
  1922.  
  1923.          /*
  1924.           * either there are no more matching files or we had an
  1925.           * invalid file name, set rc to ERROR and let's look at the
  1926.           * next file name or pattern on the command line.
  1927.           */
  1928.          else
  1929.             rc = ERROR;
  1930.       }
  1931.    }
  1932.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  1933.       /*
  1934.        * no more files to load
  1935.        */
  1936.       error( WARNING, win->bottom_line, win9 );
  1937.    return( rc );
  1938. }
  1939.  
  1940.  
  1941. /*
  1942.  * Name:    hw_fattrib
  1943.  * Purpose: To determine the current file attributes.
  1944.  * Date:    November 13, 1993
  1945.  * Passed:  name: name of file to be checked
  1946.  * Returns: use the function in the tdeasm file to get the DOS file
  1947.  *          attributes.  get_fattr() returns 0 or OK if no error.
  1948.  */
  1949. int  hw_fattrib( char *name )
  1950. {
  1951. register int rc;
  1952. mode_t fattr;
  1953.  
  1954.    rc = get_fattr( name, &fattr );
  1955.    return( rc == OK ? rc : ERROR );
  1956. }
  1957.  
  1958.  
  1959. /*
  1960.  * Name:    change_mode
  1961.  * Purpose: To prompt for file access mode.
  1962.  * Date:    November 13, 1993
  1963.  * Passed:  name:  name of file
  1964.  *          line:  line to display message
  1965.  * Returns: OK if file could be changed
  1966.  *          ERROR otherwise
  1967.  * Notes:   function is used to change file attributes for save_as function.
  1968.  */
  1969. int  change_mode( char *name, int line )
  1970. {
  1971. mode_t  fattr;
  1972. register int rc;
  1973. chtype display_buff[MAX_COLS+2];
  1974.  
  1975.    rc = get_fattr( name, &fattr );
  1976.    if (rc == OK  &&  !(fattr & S_IWUSR)) {
  1977.       /*
  1978.        * file cannot be written
  1979.        */
  1980.       save_screen_line( 0, line, display_buff );
  1981.       /*
  1982.        * file is write protected. overwrite anyway (y/n)?
  1983.        */
  1984.       set_prompt( main6, line );
  1985.       if (get_yn( ) != A_YES)
  1986.          rc = ERROR;
  1987.       else if (set_fattr( name, fattr & S_IWUSR & S_IWGRP & S_IWOTH ) != OK)
  1988.          rc = ERROR;
  1989.       restore_screen_line( 0, line, display_buff );
  1990.    }
  1991.    return( rc );
  1992. }
  1993.  
  1994.  
  1995. /*
  1996.  * Name:    change_fattr
  1997.  * Purpose: To change the file attributes
  1998.  * Date:    December 31, 1991
  1999.  * Passed:  window:  pointer to current window
  2000.  */
  2001. int  change_fattr( TDE_WIN *window )
  2002. {
  2003. file_infos *file;
  2004. TDE_WIN *wp;
  2005. int  prompt_line;
  2006. register int ok;
  2007. mode_t  fattr;
  2008. char *s;
  2009. int  rc;
  2010. char answer[MAX_COLS+2];
  2011. chtype display_buff[MAX_COLS+2];
  2012.  
  2013.    assert( window != NULL );
  2014.  
  2015.    prompt_line = window->bottom_line;
  2016.    save_screen_line( 0, prompt_line, display_buff );
  2017.  
  2018.    answer[0] = '\0';
  2019.    /*
  2020.     * enter new file attributes
  2021.     */
  2022.    rc = OK;
  2023.    if ((ok = get_name( utils14, prompt_line, answer,
  2024.                        g_display.message_color )) == OK) {
  2025.       if (*answer != '\0') {
  2026.          fattr = window->file_info->file_attrib;
  2027.  
  2028.          /*
  2029.           * turn off rwx for user, group, and other.
  2030.           */
  2031.          fattr &= ~S_IRWXU;
  2032.          fattr &= ~S_IRWXG;
  2033.          fattr &= ~S_IRWXO;
  2034.          s = answer;
  2035.  
  2036.          while (ok = toupper( *s )) {
  2037.             switch (*s) {
  2038.                case L_UNIX_READ :
  2039.                   fattr |= S_IRUSR;
  2040.                   fattr |= S_IRGRP;
  2041.                   fattr |= S_IROTH;
  2042.                   break;
  2043.                case L_UNIX_WRITE :
  2044.                   fattr |= S_IWUSR;
  2045.                   fattr |= S_IWGRP;
  2046.                   fattr |= S_IWOTH;
  2047.                   break;
  2048.                case L_UNIX_EXECUTE :
  2049.                   fattr |= S_IXUSR;
  2050.                   fattr |= S_IXGRP;
  2051.                   fattr |= S_IXOTH;
  2052.                   break;
  2053.                default :
  2054.                   break;
  2055.             }
  2056.             s++;
  2057.          }
  2058.          file = window->file_info;
  2059.          if (set_fattr( file->file_name, fattr ) == ERROR) {
  2060.             /*
  2061.              * new file attributes not set
  2062.              */
  2063.             error( WARNING, prompt_line, utils15 );
  2064.             rc = ERROR;
  2065.          } else {
  2066.             file->file_attrib = fattr;
  2067.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  2068.                if (wp->file_info == file && wp->visible)
  2069.                   show_window_fname( wp );
  2070.             }
  2071.          }
  2072.       }
  2073.    } else
  2074.       rc = ERROR;
  2075.    restore_screen_line( 0, prompt_line, display_buff );
  2076.    return( rc );
  2077. }
  2078.  
  2079.  
  2080. /*
  2081.  * Name:    get_fattr
  2082.  * Purpose: To get unix file attributes
  2083.  * Date:    November 13, 1993
  2084.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2085.  *          fattr: pointer to file attributes
  2086.  * Returns: OK if successful, ERROR if error
  2087.  * Notes:   Use stat( ) to get file attributes.
  2088.  */
  2089. int  get_fattr( char *fname, mode_t *fattr )
  2090. {
  2091. int  rc;                /* return code */
  2092. struct stat fstat;
  2093.  
  2094.    assert( fname != NULL  &&  fattr != NULL);
  2095.  
  2096.    rc = OK;
  2097.    ceh.flag = OK;
  2098.    if (stat( fname, &fstat) != ERROR)
  2099.       *fattr = fstat.st_mode;
  2100.    else
  2101.       rc = ERROR;
  2102.    if (ceh.flag == ERROR)
  2103.       rc = ERROR;
  2104.    return( rc );
  2105. }
  2106.  
  2107.  
  2108. /*
  2109.  * Name:    set_fattr
  2110.  * Purpose: To set unix file attributes
  2111.  * Date:    November 13, 1993
  2112.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2113.  *          fattr: mode_t file attributes
  2114.  * Returns: 0 if successfull, non zero if not
  2115.  * Notes:   Use chmod( ) function to set file attributes.  To change a
  2116.  *           file mode, the effective user ID of the process must equal the
  2117.  *           owner of the file, or be a superuser.
  2118.  */
  2119. int  set_fattr( char *fname, mode_t fattr )
  2120. {
  2121. int  rc;                /* return code */
  2122.  
  2123.    assert( fname != NULL );
  2124.  
  2125.    ceh.flag = OK;
  2126.    rc = OK;
  2127.    if (chmod( fname, fattr ) == ERROR)
  2128.       rc = ERROR;
  2129.    if (ceh.flag == ERROR)
  2130.       rc = ERROR;
  2131.    return( rc );
  2132. }
  2133.  
  2134.  
  2135. /*
  2136.  * Name:    get_current_directory
  2137.  * Purpose: get current directory
  2138.  * Date:    November 13, 1993
  2139.  * Passed:  path:  pointer to buffer to store path
  2140.  *          drive: drive to get current directory
  2141.  * Notes:   use simple DOS interrupt
  2142.  */
  2143. int  get_current_directory( char *path, size_t path_size )
  2144. {
  2145. register int  rc;
  2146.  
  2147.    assert( path != NULL );
  2148.  
  2149.    rc = OK;
  2150.    ceh.flag = OK;
  2151.    if (getcwd( path, path_size ) == NULL)
  2152.       rc = ERROR;
  2153.    if (ceh.flag == ERROR)
  2154.       rc = ERROR;
  2155.    return( rc );
  2156. }
  2157.  
  2158.  
  2159. /*
  2160.  * Name:    set_current_directory
  2161.  * Purpose: set current directory
  2162.  * Date:    November 13, 1993
  2163.  * Passed:  new_path: directory path, which may include drive letter
  2164.  * Notes:   use simple DOS interrupt
  2165.  */
  2166. int  set_current_directory( char *new_path )
  2167. {
  2168. register int  rc;
  2169.  
  2170.    assert( new_path != NULL );
  2171.  
  2172.    rc = OK;
  2173.    ceh.flag = OK;
  2174.    if( chdir( new_path ) == ERROR)
  2175.       rc = ERROR;
  2176.    if (ceh.flag == ERROR)
  2177.       rc = ERROR;
  2178.    return( rc );
  2179. }
  2180.  
  2181. #else
  2182. /*
  2183.  **********************************************************************
  2184.  ******************************  PART 2  ******************************
  2185.  **********************************************************************
  2186.  *
  2187.  * Calls to BIOS and writes to PC hardware.
  2188.  */
  2189.  
  2190.  
  2191. /*
  2192.  * Name:    make_backup_fname
  2193.  * Purpose: add .bak to file name
  2194.  * Date:    January 6, 1992
  2195.  * Passed:  file: information allowing access to the current file
  2196.  */
  2197. void make_backup_fname( file_infos *file )
  2198. {
  2199. char *p;
  2200. int  i;
  2201. int  len;
  2202. char temp[MAX_COLS+2];
  2203.  
  2204.    /*
  2205.     * if this is a new file then don't create a backup - can't backup
  2206.     *   a nonexisting file.
  2207.     */
  2208.    if (file->new_file)
  2209.       file->backed_up = TRUE;
  2210.  
  2211.    /*
  2212.     * find the file name extension if it exists
  2213.     */
  2214.    else {
  2215.       assert( strlen( file->file_name ) < (size_t)g_display.ncols );
  2216.  
  2217.       strcpy( temp, file->file_name );
  2218.       len = strlen( temp );
  2219.       for (i=len, p=temp + len; i>=0; i--) {
  2220.  
  2221.          /*
  2222.           * we found the '.' extension character.  get out
  2223.           */
  2224.          if (*p == '.')
  2225.             break;
  2226.  
  2227.          /*
  2228.           * we found the drive or directory character.  no extension so
  2229.           *  set the pointer to the end of file name string.
  2230.           */
  2231.          else if (*p == '\\' || *p == ':') {
  2232.             p = temp + len;
  2233.             break;
  2234.  
  2235.          /*
  2236.           * we're at the beginning of the string - no '.', drive, or directory
  2237.           *  char was found.  set the pointer to the end of file name string.
  2238.           */
  2239.          } else if (i == 0) {
  2240.             p = temp + len;
  2241.             break;
  2242.          }
  2243.          --p;
  2244.       }
  2245.       assert( strlen( temp ) < (size_t)g_display.ncols );
  2246.       strcpy( p, ".bak" );
  2247.       strcpy( file->backup_fname, temp );
  2248.    }
  2249. }
  2250.  
  2251.  
  2252. /*
  2253.  * Name:    write_to_disk
  2254.  * Purpose: To write file from memory to disk
  2255.  * Date:    June 5, 1991
  2256.  * Passed:  window:  pointer to current window
  2257.  *          fname:   file name to save on disk
  2258.  */
  2259. int  write_to_disk( TDE_WIN *window, char *fname )
  2260. {
  2261. register file_infos *file;
  2262. int  rc;
  2263. int  prompt_line;
  2264. char temp[MAX_COLS+2];
  2265. char answer[MAX_COLS+2];
  2266. char display_buff[(MAX_COLS+2)*2];
  2267. int  fattr;
  2268.  
  2269.    file = window->file_info;
  2270.    prompt_line = window->bottom_line;
  2271.  
  2272.    /*
  2273.     * set up file name
  2274.     */
  2275.    assert( strlen( fname ) < (size_t)g_display.ncols );
  2276.  
  2277.    strcpy( answer, fname );
  2278.    save_screen_line( 0, prompt_line, display_buff );
  2279.    eol_clear( 0, prompt_line, g_display.message_color );
  2280.  
  2281.    /*
  2282.     * saving
  2283.     */
  2284.    combine_strings( temp, utils6, answer, "'" );
  2285.    s_output( temp, prompt_line, 0, g_display.message_color );
  2286.    if ((rc = hw_save( answer, file, 1L, file->length, NOTMARKED )) == ERROR) {
  2287.       if (ceh.flag != ERROR) {
  2288.          if (get_fattr( answer, &fattr ) == OK && fattr & READ_ONLY)
  2289.             /*
  2290.              * file is read only
  2291.              */
  2292.             combine_strings( temp, utils7a, answer, utils7b );
  2293.          else
  2294.             /*
  2295.              * cannot write to
  2296.              */
  2297.             combine_strings( temp, utils8, answer, "'" );
  2298.          error( WARNING, prompt_line, temp );
  2299.       }
  2300.    }
  2301.    restore_screen_line( 0, prompt_line, display_buff );
  2302.    return( rc );
  2303. }
  2304.  
  2305.  
  2306. /*
  2307.  * Name:    search_and_seize
  2308.  * Purpose: search files for a pattern
  2309.  * Date:    October 31, 1992
  2310.  * Passed:  window:  pointer to current window
  2311.  * Notes:   New window replaces old window.  Old window becomes invisible.
  2312.  */
  2313. int  search_and_seize( TDE_WIN *window )
  2314. {
  2315. char name[MAX_COLS];            /* new name for file */
  2316. char searching[MAX_COLS];       /* buffer for displaying file name */
  2317. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  2318. char spdir[_MAX_DIR];           /* splitpath dir buff */
  2319. char spname[_MAX_FNAME];        /* splitpath fname buff */
  2320. char spext[_MAX_EXT];           /* splitpath ext buff */
  2321. int  file_mode;
  2322. int  bin_length;
  2323. int  i;
  2324. int  update_type;
  2325. char *tokens;
  2326. register int rc = ERROR;
  2327. register TDE_WIN *win;           /* put window pointer in a register */
  2328. int  bottom_line;
  2329. char display_buff[(MAX_COLS+2)*2];
  2330.  
  2331.    win = window;
  2332.    update_type = win == NULL ? GLOBAL : LOCAL;
  2333.    if (update_type == LOCAL) {
  2334.       if (!g_status.sas_defined ||  g_status.command == DefineGrep ||
  2335.                               g_status.command == DefineRegXGrep) {
  2336.  
  2337.          /*
  2338.           * prompt for the search pattern and the seize path.
  2339.           *   initialize all this stuff.
  2340.           */
  2341.          if (g_status.command == DefineGrep)
  2342.             g_status.sas_search_type = BOYER_MOORE;
  2343.          else
  2344.             g_status.sas_search_type = REG_EXPRESSION;
  2345.  
  2346.          if (g_status.sas_search_type == BOYER_MOORE) {
  2347.             *sas_bm.pattern = '\0';
  2348.             if (get_name( win16a, win->bottom_line, (char *)sas_bm.pattern,
  2349.                              g_display.message_color ) == ERROR)
  2350.                return( ERROR );
  2351.             if (*sas_bm.pattern == '\0')
  2352.                return( ERROR );
  2353.          } else {
  2354.             *sas_regx.pattern = '\0';
  2355.             if (get_name( win16b, win->bottom_line, (char *)sas_regx.pattern,
  2356.                              g_display.message_color ) == ERROR)
  2357.                return( ERROR );
  2358.             if (*sas_regx.pattern == '\0')
  2359.                return( ERROR );
  2360.             else
  2361.                strcpy( (char *)regx.pattern, (char *)sas_regx.pattern );
  2362.          }
  2363.          *g_status.sas_tokens = '\0';
  2364.          if (get_name( win17, win->bottom_line, g_status.sas_tokens,
  2365.                           g_display.message_color ) == ERROR)
  2366.             return( ERROR );
  2367.          i = 0;
  2368.          tokens = strtok( g_status.sas_tokens, SAS_DELIMITERS );
  2369.          while (tokens != NULL) {
  2370.             g_status.sas_arg_pointers[i++] = tokens;
  2371.             tokens = strtok( NULL, SAS_DELIMITERS );
  2372.          }
  2373.          if (i == 0)
  2374.             return( ERROR );
  2375.          g_status.sas_arg_pointers[i] = NULL;
  2376.          g_status.sas_argc = i;
  2377.          g_status.sas_arg = 0;
  2378.          g_status.sas_argv = g_status.sas_arg_pointers;
  2379.          g_status.sas_found_first = FALSE;
  2380.          if (g_status.command == DefineGrep) {
  2381.             g_status.sas_defined = TRUE;
  2382.             bm.search_defined = sas_bm.search_defined = OK;
  2383.             build_boyer_array( );
  2384.          } else {
  2385.             i = build_nfa( );
  2386.             if (i == OK) {
  2387.                g_status.sas_defined = TRUE;
  2388.                regx.search_defined = sas_regx.search_defined = OK;
  2389.             } else
  2390.                g_status.sas_defined = FALSE;
  2391.          }
  2392.       }
  2393.       bottom_line = win->bottom_line;
  2394.    } else
  2395.       bottom_line = g_display.nlines;
  2396.    if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  2397.       if (win != NULL) {
  2398.          entab_linebuff( );
  2399.          un_copy_line( win->ll, win, TRUE );
  2400.       }
  2401.  
  2402.       /*
  2403.        * while we haven't found a valid file, search thru the command
  2404.        * line path.
  2405.        * we may have an invalid file name when we finish matching all
  2406.        * files according to a pattern.  then, we need to go to the next
  2407.        * command line argument if it exists.
  2408.        */
  2409.       while (rc == ERROR && g_status.sas_arg < g_status.sas_argc) {
  2410.  
  2411.          /*
  2412.           * if we haven't starting searching for a file, check to see if
  2413.           * the file is a valid file name.  if no file is found, then let's
  2414.           * see if we can find according to a search pattern.
  2415.           */
  2416.          if (g_status.sas_found_first == FALSE) {
  2417.  
  2418.             assert( strlen( g_status.sas_argv[g_status.sas_arg] )
  2419.                         < (size_t)g_display.ncols );
  2420.  
  2421.             strcpy( name, g_status.sas_argv[g_status.sas_arg] );
  2422.             rc = get_fattr( name, &i );
  2423.  
  2424.             /*
  2425.              * a new or blank file generates a return code of 2.
  2426.              * a pattern with wild cards generates a return code of 3.
  2427.              */
  2428.             if (rc == OK || rc == 2) {
  2429.                ++g_status.sas_arg;
  2430.                rc = OK;
  2431.  
  2432.             /*
  2433.              * if we get this far, we got an invalid path name.
  2434.              *  let's try to find a matching file name using pattern.
  2435.              */
  2436.             } else if (rc != ERROR) {
  2437.                rc = my_findfirst( &g_status.sas_dta, name, NORMAL | READ_ONLY |
  2438.                                HIDDEN | SYSTEM | ARCHIVE );
  2439.  
  2440.                /*
  2441.                 * if we found a file using wildcard characters,
  2442.                 * set the g_status.sas_found_first flag to true so we can
  2443.                 * find the next matching file.  we need to save the
  2444.                 * pathname stem so we know which directory we are working in.
  2445.                 */
  2446.                if (rc == OK) {
  2447.                   g_status.sas_found_first = TRUE;
  2448.                   i = strlen( name ) - 1;
  2449.                   while (i >= 0) {
  2450.                      if (name[i] == ':' || name[i] == '\\')
  2451.                         break;
  2452.                      --i;
  2453.                   }
  2454.                   name[++i] = '\0';
  2455.  
  2456.                   assert( strlen( name ) + strlen( g_status.sas_dta.name )
  2457.                                    < (size_t)g_display.ncols );
  2458.  
  2459.                   strcpy( g_status.sas_path, name );
  2460.                   strcpy( name, g_status.sas_path );
  2461.                   strcat( name, g_status.sas_dta.name );
  2462.                } else {
  2463.                   ++g_status.sas_arg;
  2464.                   if (win != NULL)
  2465.                      /*
  2466.                       * invalid path or file name
  2467.                       */
  2468.                      error( WARNING, win->bottom_line, win8 );
  2469.                }
  2470.             } else if (rc == ERROR)
  2471.                ++g_status.sas_arg;
  2472.          } else {
  2473.  
  2474.             /*
  2475.              * we already found one file with wild card characters,
  2476.              * find the next matching file.
  2477.              */
  2478.             rc = my_findnext( &g_status.sas_dta );
  2479.             if (rc == OK) {
  2480.  
  2481.                assert( strlen( g_status.sas_path ) +
  2482.                    strlen( g_status.sas_dta.name ) < (size_t)g_display.ncols );
  2483.  
  2484.                strcpy( name, g_status.sas_path );
  2485.                strcat( name, g_status.sas_dta.name );
  2486.             } else {
  2487.                g_status.sas_found_first = FALSE;
  2488.                ++g_status.sas_arg;
  2489.             }
  2490.          }
  2491.  
  2492.          /*
  2493.           * if everything is everything so far, set up the file
  2494.           * and window structures and bring the file into the editor.
  2495.           */
  2496.          if (rc == OK) {
  2497.  
  2498.             assert( strlen( win19 ) + strlen( name ) < (size_t)g_display.ncols );
  2499.  
  2500.             strcpy( searching, win19 );
  2501.             strcat( searching, name );
  2502.             save_screen_line( 0, bottom_line, display_buff );
  2503.             set_prompt( searching, bottom_line );
  2504.             file_mode = TEXT;
  2505.             bin_length = 0;
  2506.  
  2507.             assert( strlen( name ) <= (size_t)g_display.ncols );
  2508.  
  2509.             _splitpath( name, spdrive, spdir, spname, spext );
  2510.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0){
  2511.                file_mode = BINARY;
  2512.                bin_length = g_status.file_chunk;
  2513.             }
  2514.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  2515.             if (rc == OK)
  2516.                show_avail_mem( );
  2517.             restore_screen_line( 0, bottom_line, display_buff );
  2518.  
  2519.             if (rc == OK) {
  2520.                win = g_status.current_window;
  2521.                bin_offset_adjust( win, g_status.sas_rline );
  2522.                find_adjust( win, g_status.sas_ll, g_status.sas_rline,
  2523.                             g_status.sas_rcol );
  2524.                make_ruler( win );
  2525.                show_ruler( win );
  2526.                show_ruler_pointer( win );
  2527.                show_window_header( win );
  2528.                if (win->vertical)
  2529.                   show_vertical_separator( win );
  2530.                win->file_info->dirty = LOCAL;
  2531.             }
  2532.          }
  2533.  
  2534.          /*
  2535.           * either there are no more matching files or we had an
  2536.           * invalid file name, set rc to ERROR and let's look at the
  2537.           * next file name or pattern on the command line.
  2538.           */
  2539.          else
  2540.             rc = ERROR;
  2541.       }
  2542.    }
  2543.    if (rc == ERROR &&  g_status.sas_arg >= g_status.sas_argc  && win != NULL)
  2544.       /*
  2545.        * no more files to load
  2546.        */
  2547.       error( WARNING, win->bottom_line, win9 );
  2548.    return( rc );
  2549. }
  2550.  
  2551.  
  2552. /*
  2553.  * Name:    edit_next_file
  2554.  * Purpose: edit next file on command line.
  2555.  * Date:    January 6, 1992
  2556.  * Passed:  window:  pointer to current window
  2557.  * Notes:   New window replaces old window.  Old window becomes invisible.
  2558.  */
  2559. int  edit_next_file( TDE_WIN *window )
  2560. {
  2561. char name[MAX_COLS];            /* new name for file */
  2562. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  2563. char spdir[_MAX_DIR];           /* splitpath dir buff */
  2564. char spname[_MAX_FNAME];        /* splitpath fname buff */
  2565. char spext[_MAX_EXT];           /* splitpath ext buff */
  2566. int  file_mode;
  2567. int  bin_length;
  2568. int  i;
  2569. int  update_type;
  2570. register int rc = ERROR;
  2571. register TDE_WIN *win;           /* put window pointer in a register */
  2572.  
  2573.    win = window;
  2574.    update_type = win == NULL ? GLOBAL : LOCAL;
  2575.    if (g_status.arg < g_status.argc) {
  2576.       if (win != NULL) {
  2577.          entab_linebuff( );
  2578.          if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2579.             return( ERROR );
  2580.       }
  2581.  
  2582.       /*
  2583.        * while we haven't found a valid file, search thru the command
  2584.        * line path.
  2585.        * we may have an invalid file name when we finish matching all
  2586.        * files according to a pattern.  then, we need to go to the next
  2587.        * command line argument if it exists.
  2588.        */
  2589.       while (rc == ERROR && g_status.arg < g_status.argc) {
  2590.  
  2591.          /*
  2592.           * if we haven't starting searching for a file, check to see if
  2593.           * the file is a valid file name.  if no file is found, then let's
  2594.           * see if we can find according to a search pattern.
  2595.           */
  2596.          if (g_status.found_first == FALSE) {
  2597.  
  2598.             assert( strlen( g_status.argv[g_status.arg] ) <
  2599.                                              (size_t)g_display.ncols );
  2600.  
  2601.             strcpy( name, g_status.argv[g_status.arg] );
  2602.             rc = get_fattr( name, &i );
  2603.  
  2604.             /*
  2605.              * a new or blank file generates a return code of 2.
  2606.              * a pattern with wild cards generates a return code of 3.
  2607.              */
  2608.             if (rc == OK || rc == 2) {
  2609.                ++g_status.arg;
  2610.                rc = OK;
  2611.  
  2612.             /*
  2613.              * if we get this far, we got an invalid path name.
  2614.              *  let's try to find a matching file name using pattern.
  2615.              */
  2616.             } else if (rc != ERROR) {
  2617.                rc = my_findfirst( &g_status.dta, name, NORMAL | READ_ONLY |
  2618.                                HIDDEN | SYSTEM | ARCHIVE );
  2619.  
  2620.                /*
  2621.                 * if we found a file using wildcard characters,
  2622.                 * set the g_status.found_first flag to true so we can
  2623.                 * find the next matching file.  we need to save the
  2624.                 * pathname stem so we know which directory we are working in.
  2625.                 */
  2626.                if (rc == OK) {
  2627.                   g_status.found_first = TRUE;
  2628.                   i = strlen( name ) - 1;
  2629.                   while (i >= 0) {
  2630.                      if (name[i] == ':' || name[i] == '\\')
  2631.                         break;
  2632.                      --i;
  2633.                   }
  2634.                   name[++i] = '\0';
  2635.  
  2636.                   assert( strlen( name ) < (size_t)g_display.ncols );
  2637.  
  2638.                   strcpy( g_status.path, name );
  2639.                   strcpy( name, g_status.path );
  2640.                   strcat( name, g_status.dta.name );
  2641.                } else {
  2642.                   ++g_status.arg;
  2643.                   if (win != NULL)
  2644.                      /*
  2645.                       * invalid path or file name
  2646.                       */
  2647.                      error( WARNING, win->bottom_line, win8 );
  2648.                }
  2649.             } else if (rc == ERROR)
  2650.                ++g_status.arg;
  2651.          } else {
  2652.  
  2653.             /*
  2654.              * we already found one file with wild card characters,
  2655.              * find the next matching file.
  2656.              */
  2657.             rc = my_findnext( &g_status.dta );
  2658.             if (rc == OK) {
  2659.  
  2660.                assert( strlen( g_status.path ) + strlen( g_status.dta.name )
  2661.                            < (size_t)g_display.ncols );
  2662.  
  2663.                strcpy( name, g_status.path );
  2664.                strcat( name, g_status.dta.name );
  2665.             } else {
  2666.                g_status.found_first = FALSE;
  2667.                ++g_status.arg;
  2668.             }
  2669.          }
  2670.  
  2671.          /*
  2672.           * if everything is everything so far, set up the file
  2673.           * and window structures and bring the file into the editor.
  2674.           */
  2675.          if (rc == OK) {
  2676.             file_mode = g_status.file_mode;
  2677.             bin_length = g_status.file_chunk;
  2678.  
  2679.             assert( strlen( name ) <= (size_t)g_display.ncols );
  2680.  
  2681.             _splitpath( name, spdrive, spdir, spname, spext );
  2682.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0)
  2683.                file_mode = BINARY;
  2684.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  2685.             if (rc == OK)
  2686.                show_avail_mem( );
  2687.          }
  2688.  
  2689.          /*
  2690.           * either there are no more matching files or we had an
  2691.           * invalid file name, set rc to ERROR and let's look at the
  2692.           * next file name or pattern on the command line.
  2693.           */
  2694.          else
  2695.             rc = ERROR;
  2696.       }
  2697.    }
  2698.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  2699.       /*
  2700.        * no more files to load
  2701.        */
  2702.       error( WARNING, win->bottom_line, win9 );
  2703.    return( rc );
  2704. }
  2705.  
  2706.  
  2707. /*
  2708.  * Name:    hw_fattrib
  2709.  * Purpose: To determine the current file attributes.
  2710.  * Date:    December 26, 1991
  2711.  * Passed:  name: name of file to be checked
  2712.  * Returns: use the function in the tdeasm file to get the DOS file
  2713.  *          attributes.  get_fattr() returns 0 or OK if no error.
  2714.  */
  2715. int  hw_fattrib( char *name )
  2716. {
  2717. register int rc;
  2718. int  fattr;
  2719.  
  2720.    rc = get_fattr( name, &fattr );
  2721.    return( rc == OK ? rc : ERROR );
  2722. }
  2723.  
  2724.  
  2725. /*
  2726.  * Name:    change_mode
  2727.  * Purpose: To prompt for file access mode.
  2728.  * Date:    January 11, 1992
  2729.  * Passed:  name:  name of file
  2730.  *          line:  line to display message
  2731.  * Returns: OK if file could be changed
  2732.  *          ERROR otherwise
  2733.  * Notes:   function is used to change file attributes for save_as function.
  2734.  */
  2735. int  change_mode( char *name, int line )
  2736. {
  2737. int  result;
  2738. int  fattr;
  2739. register int rc;
  2740. char display_buff[(MAX_COLS+2)*2];
  2741.  
  2742.    rc = OK;
  2743.    result = get_fattr( name, &fattr );
  2744.    if (result != OK)
  2745.       rc = ERROR;
  2746.    else if (result == OK && fattr & READ_ONLY) {
  2747.       /*
  2748.        * file is read only
  2749.        */
  2750.       save_screen_line( 0, line, display_buff );
  2751.       /*
  2752.        * file is write protected. overwrite anyway (y/n)?
  2753.        */
  2754.       set_prompt( main6, line );
  2755.       if (get_yn( ) != A_YES)
  2756.          rc = ERROR;
  2757.       if (rc == OK && set_fattr( name, ARCHIVE ) != OK)
  2758.          rc = ERROR;
  2759.       restore_screen_line( 0, line, display_buff );
  2760.    }
  2761.    return( rc );
  2762. }
  2763.  
  2764.  
  2765. /*
  2766.  * Name:    change_fattr
  2767.  * Purpose: To change the file attributes
  2768.  * Date:    December 31, 1991
  2769.  * Passed:  window:  pointer to current window
  2770.  */
  2771. int  change_fattr( TDE_WIN *window )
  2772. {
  2773. file_infos *file;
  2774. TDE_WIN *wp;
  2775. int  prompt_line;
  2776. register int ok;
  2777. unsigned char fattr;
  2778. char *s;
  2779. int  rc;
  2780. char answer[MAX_COLS+2];
  2781. char display_buff[(MAX_COLS+2)*2];
  2782.  
  2783.    prompt_line = window->bottom_line;
  2784.    save_screen_line( 0, prompt_line, display_buff );
  2785.  
  2786.    answer[0] = '\0';
  2787.    /*
  2788.     * enter new file attributes
  2789.     */
  2790.    if ((ok = get_name( utils14, prompt_line, answer,
  2791.                        g_display.message_color )) == OK) {
  2792.       if (*answer != '\0') {
  2793.          fattr = 0;
  2794.          s = answer;
  2795.  
  2796.          /*
  2797.           * yes, I know lint complains about "ok = *s++".
  2798.           */
  2799.          while (ok = toupper( *s )) {
  2800.             switch (ok) {
  2801.                case L_DOS_ARCHIVE :
  2802.                   fattr |= ARCHIVE;
  2803.                   break;
  2804.                case L_DOS_SYSTEM :
  2805.                   fattr |= SYSTEM;
  2806.                   break;
  2807.                case L_DOS_HIDDEN :
  2808.                   fattr |= HIDDEN;
  2809.                   break;
  2810.                case L_DOS_READ_ONLY :
  2811.                   fattr |= READ_ONLY;
  2812.                   break;
  2813.                default :
  2814.                   break;
  2815.             }
  2816.             s++;
  2817.          }
  2818.          file = window->file_info;
  2819.          if (set_fattr( file->file_name, fattr ))
  2820.             /*
  2821.              * new file attributes not set
  2822.              */
  2823.             error( WARNING, prompt_line, utils15 );
  2824.          else {
  2825.             file->file_attrib = fattr;
  2826.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  2827.                if (wp->file_info == file && wp->visible)
  2828.                   show_window_fname( wp );
  2829.             }
  2830.          }
  2831.       }
  2832.       rc = OK;
  2833.    } else
  2834.       rc = ERROR;
  2835.    restore_screen_line( 0, prompt_line, display_buff );
  2836.    return( rc );
  2837. }
  2838.  
  2839.  
  2840. /*
  2841.  * Name:    get_fattr
  2842.  * Purpose: To get dos file attributes
  2843.  * Date:    December 26, 1991
  2844.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2845.  *          fattr: pointer to file attributes
  2846.  * Returns: 0 if successfull, non zero if not
  2847.  * Notes:   Uses the DOS function to get file attributes.  I really didn't
  2848.  *           like the file attribute functions in the C library:  fstat() and
  2849.  *           stat() or access() and chmod().
  2850.  *           FYI, File Attributes:
  2851.  *              0x00 = Normal.  Can be read or written w/o restriction
  2852.  *              0x01 = Read-only.  Cannot be opened for write; a file with
  2853.  *                     the same name cannot be created.
  2854.  *              0x02 = Hidden.  Not found by directory search.
  2855.  *              0x04 = System.  Not found by directory search.
  2856.  *              0x08 = Volumn Label.
  2857.  *              0x10 = Directory.
  2858.  *              0x20 = Archive.  Set whenever the file is changed, or
  2859.  *                     cleared by the Backup command.
  2860.  *           Return codes:
  2861.  *              0 = No error
  2862.  *              1 = AL not 0 or 1
  2863.  *              2 = file is invalid or does not exist
  2864.  *              3 = path is invalid or does not exist
  2865.  *              5 = Access denied
  2866.  */
  2867. int  get_fattr( char FAR *fname, int *fattr )
  2868. {
  2869. int  rc;                /* return code */
  2870. int  attr;
  2871.  
  2872.    ASSEMBLE {
  2873.         push    ds
  2874.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  2875.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  2876.         mov     ds, ax                  /* put SEGMENT in ds */
  2877.         mov     ax, 0x4300              /* function:  get file attributes */
  2878.         int     0x21                    /* DOS interrupt */
  2879.         pop     ds
  2880.  
  2881.         jc      an_error                /* save the error code from get attr */
  2882.         xor     ax, ax                  /* if no carry, no error */
  2883.         jmp     SHORT get_out           /* lets get out */
  2884.    }
  2885. an_error:
  2886.  
  2887.  
  2888.    ASSEMBLE {
  2889.         xor     cx, cx                  /* if error, then zero out cx - attrs */
  2890.    }
  2891. get_out:
  2892.  
  2893.    ASSEMBLE {
  2894.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  2895.         mov     WORD PTR attr, cx       /* cx contains file attributes */
  2896.    }
  2897.    *fattr = attr;
  2898.    if (ceh.flag == ERROR)
  2899.       rc = ERROR;
  2900.    return( rc );
  2901. }
  2902.  
  2903.  
  2904. /*
  2905.  * Name:    set_fattr
  2906.  * Purpose: To set dos file attributes
  2907.  * Date:    December 26, 1991
  2908.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2909.  *          fattr: file attributes
  2910.  * Returns: 0 if successfull, non zero if not
  2911.  * Notes:   Uses the DOS function to get file attributes.
  2912.  *           Return codes:
  2913.  *              0 = No error
  2914.  *              1 = AL not 0 or 1
  2915.  *              2 = file is invalid or does not exist
  2916.  *              3 = path is invalid or does not exist
  2917.  *              5 = Access denied
  2918.  */
  2919. int  set_fattr( char FAR *fname, int fattr )
  2920. {
  2921. int  rc;                /* return code */
  2922.  
  2923.    ASSEMBLE {
  2924.         push    ds
  2925.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  2926.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  2927.         mov     ds, ax                  /* put SEGMENT in ds */
  2928.         mov     cx, WORD PTR fattr      /* cx contains file attributes */
  2929.         mov     ax, 0x4301              /* function:  get file attributes */
  2930.         int     0x21                    /* DOS interrupt */
  2931.         pop     ds
  2932.  
  2933.         jc      get_out                 /* save the error code from get attr */
  2934.         xor     ax, ax                  /* if no carry, no error */
  2935.    }
  2936. get_out:
  2937.  
  2938.    ASSEMBLE {
  2939.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  2940.    }
  2941.    if (ceh.flag == ERROR)
  2942.       rc = ERROR;
  2943.    return( rc );
  2944. }
  2945.  
  2946.  
  2947. /*
  2948.  * Name:    get_current_directory
  2949.  * Purpose: get current directory
  2950.  * Date:    February 13, 1992
  2951.  * Passed:  path:  pointer to buffer to store path
  2952.  *          drive: drive to get current directory
  2953.  * Notes:   use simple DOS interrupt
  2954.  */
  2955. int  get_current_directory( char FAR *path, int drive )
  2956. {
  2957. int  rc;
  2958.  
  2959.    ASSEMBLE {
  2960.         push    si                      /* save register vars if any */
  2961.         push    ds                      /* save ds */
  2962.  
  2963.         mov     dx, WORD PTR drive      /* dl = drive, 0 = default, 1 = a, etc.. */
  2964.         mov     si, WORD PTR path       /* get OFFSET of path */
  2965.         mov     ax, WORD PTR path+2     /* get SEGMENT of path */
  2966.         mov     ds, ax                  /* put it in ds */
  2967.         mov     ah, 0x47                /* function 0x47 == get current dir */
  2968.         int     0x21                    /* standard DOS interrupt */
  2969.         xor     ax, ax                  /* zero out ax, return OK if no error */
  2970.         jnc     no_error                /* if carry set, then an error */
  2971.         mov     ax, ERROR               /* return -1 if error */
  2972.    }
  2973. no_error:
  2974.  
  2975.    ASSEMBLE {
  2976.         pop     ds                      /* get back ds */
  2977.         pop     si                      /* get back si */
  2978.         mov     WORD PTR rc, ax         /* save return code */
  2979.    }
  2980.    if (ceh.flag == ERROR)
  2981.       rc = ERROR;
  2982.    return( rc );
  2983. }
  2984.  
  2985.  
  2986. /*
  2987.  * Name:    set_current_directory
  2988.  * Purpose: set current directory
  2989.  * Date:    February 13, 1992
  2990.  * Passed:  new_path: directory path, which may include drive letter
  2991.  * Notes:   use simple DOS interrupt
  2992.  */
  2993. int  set_current_directory( char FAR *new_path )
  2994. {
  2995. int  rc;
  2996.  
  2997.    ASSEMBLE {
  2998.         push    ds                      /* save ds */
  2999.  
  3000.         mov     dx, WORD PTR new_path   /* get OFFSET of new_path */
  3001.         mov     ax, WORD PTR new_path+2 /* get SEGMENT of new_path */
  3002.         mov     ds, ax                  /* put it in ds */
  3003.         mov     ah, 0x3b                /* function 0x3b == set current dir */
  3004.         int     0x21                    /* standard DOS interrupt */
  3005.         xor     ax, ax                  /* zero out ax, return OK if no error */
  3006.         jnc     no_error                /* if carry set, then an error */
  3007.         mov     ax, ERROR               /* return -1 if error */
  3008.    }
  3009. no_error:
  3010.  
  3011.    ASSEMBLE {
  3012.         pop     ds                      /* get back ds */
  3013.         mov     WORD PTR rc, ax         /* save return code */
  3014.    }
  3015.    if (ceh.flag == ERROR)
  3016.       rc = ERROR;
  3017.    return( rc );
  3018. }
  3019. #endif
  3020.